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())
source to share
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.
source to share