I have a coroutine (Enhanced generators) in python with some code to be executed after the end of data:
def mycoroutine():
try:
while True:
data = (yield)
print data
finally:
raise ValueError
print "END"
co = mycoroutine()
co.next()
for i in (1,2,3):
co.send(i)
The ValueError
exception is not raised but the interpreter simply prints:
Exception ValueError: ValueError() in <generator object mycoroutine at 0x2b59dfa23d20> ignored
Is there a way to catch the exception in the caller?
The exception is raised. The finally
block is executed when the generator is closed. Closing a generator is done by raising a GeneratorExit
exception in the generator context.
The exception in ignored because the generator isn't closed until it is being deleted (automatically in this case, when Python exits); the generator __del__
handler closes the generator, which triggers the finally:
block:
>>> def mycoroutine():
... try:
... while True:
... data = (yield)
... print data
... finally:
... raise ValueError
... print "END"
...
>>> co = mycoroutine()
>>> co.next()
>>> co.close()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in mycoroutine
ValueError
>>> co = mycoroutine()
>>> co.next()
>>> del co
Exception ValueError: ValueError() in <generator object mycoroutine at 0x1046a9fa0> ignored
Exceptions raised during cleanup are always ignored; see the object.__del__()
documentation:
Warning: Due to the precarious circumstances under which
__del__()
methods are invoked, exceptions that occur during their execution are ignored, and a warning is printed tosys.stderr
instead.
The solution is to not have exceptions being raised when a generator is cleaned up, or catch the exception by closing the generator explicitly:
>>> co = mycoroutine()
>>> co.next()
>>> try:
... co.close()
... except ValueError:
... pass
...
>>> del co
>>> # No exception was raised
...
You could also catch the GeneratorExit
exception and perform some cleanup at that point:
def mycoroutine():
try:
while True:
data = (yield)
print data
except GeneratorExit:
print "Generator exiting!"
but note that any exception other than StopIteration
or GeneratorExit
will always be propagated; see the generator.close()
documentation:
If the generator function then raises
StopIteration
(by exiting normally, or due to already being closed) orGeneratorExit
(by not catching the exception), close returns to its caller. If the generator yields a value, aRuntimeError
is raised. If the generator raises any other exception, it is propagated to the caller.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With