I recently came across some surprising behaviour in Python generators:
class YieldOne:
def __iter__(self):
try:
yield 1
except:
print '*Excepted Successfully*'
# raise
for i in YieldOne():
raise Exception('test exception')
Which gives the output:
*Excepted Successfully*
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
Exception: test exception
I was (pleasantly) surprised that *Excepted Successfully* got printed, as this was what I wanted, but also surprised that the Exception still got propagated up to the top level. I was expecting to have to use the (commented in this example) raise keyword to get the observed behaviour.
Can anyone explain why this functionality works as it does, and why the except in the generator doesn’t swallow the exception?
Is this the only instance in Python where an except doesn’t swallow an exception?
Your code does not do what you think it does. You cannot raise Exceptions in a coroutine like this. What you do instead is catching the
GeneratorExitexception. See what happens when you use a different Exception:As this still gets upvotes, here is how you raise an Exception in a generator:
See docs for
generator.throw.