Throw exception thrown by calling generator in Python

I'm trying to catch the exception thrown in the calling generator:

class MyException(Exception):
    pass

def gen():
    for i in range(3):
        try:
            yield i
        except MyException:
            print 'handled exception'

for i in gen():
    print i
    raise MyException

      

Outputs

$ python x.py
0
Traceback (most recent call last):
  File "x.py", line 14, in <module>
    raise MyException
__main__.MyException

      

when i was going to withdraw

$ python x.py
0
handled exception
1
handled exception
2
handled exception

      

In retrospect, I think it has to do with the fact that the caller has a different stack from the generator, so the exception is not blown up to the generator. It is right? Is there any other way to catch exceptions thrown in the caller?

Also: I can get it to work with generator.throw () , but this requires changing the caller:

def gen():
    for i in range(3):
        try:
            yield i
        except MyException:
            print 'handled exception'
            yield

import sys
g = gen()
for i in g:
    try:
        print i
        raise MyException
    except:
        g.throw(*sys.exc_info())

      

+3


source to share


1 answer


You might be thinking that when executed in a generator, the yield

generator executes the loop body for

, like a Ruby function with a yield

block. This is not how things work in Python.

When execution reaches yield

, the generator stack frame is paused and popped off the stack, and control returns to code that is (implicitly) called the generator next

. This code then goes into the body of the loop. At the time the exception is thrown, the generator's stack frame is not on the stack, and the exception does not travel through the generator when it bubbles up.



The generator has no way of responding to this exception.

+4


source







All Articles