Errors in local generators cannot be caught

Hi,
I noticed that the exception handler does not catch an exception raised from the local generator. This seems to be a bug; Otherwise, it could be a design, but I’d like to hear some opinions before reporting it to the bug tracker.
This is the test code:

def g(n):
    try:
        def _g():
            ## return range(n)  # ok: An error from range will be caught.
            yield from range(n)  # NG: A generator error can't be caught.
        return _g()
    except Exception as e:
        print(e)
        return []
print(list(g(None))) 

which gives the following traceback message:

Traceback (most recent call last):
  File "C:\usr\home\lib\python\test-py\py3_issue_gen2.py", line 23, in <module>
    print(list(g(None)))
  File "C:\usr\home\lib\python\test-py\py3_issue_gen2.py", line 16, in _g
    yield from range(n)  # NG: A generator error can't be caught.
TypeError: 'NoneType' object cannot be interpreted as an integer

Python 3.10.11

Unlike an ordinary function, calling a generator function does not execute its body, but instead returns a generator iterator. Only when you iterate over that does the body of the function get run. In your example:

  1. Inside the try block, the generator function _g is created, it’s called to get a generator iterator, and that is returned from g.
  2. Outside of the try block (and outside the g function), the generator iterator is passed to the list constructor, which iterates over it. It’s then that the body of _g runs, and the exception gets raised. That is why it is not handled.
2 Likes

J, thank you very much for your clear explanation!
I got the proper way to write like this.

def g(n):
    def _g():
        try:
            yield from range(n)
        except Exception as e:
            print(_g, e)
    try:
        return _g()
    except Exception as e:
        pass

K

1 Like