Avoid ignoring exceptions in a python extension generator

I have coroutine (Enhanced generators) in python with some code that will be executed after the data ends:

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) 

A ValueError exception is not thrown, 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?

+6
source share
1 answer

Excluded. The finally block is executed when the generator is closed. Closing a generator is done by creating a GeneratorExit exception in the context of the generator.

The exception is ignored because the generator is not closed until it is deleted (automatically in this case, when Python exits); the __del__ generator closes the generator that runs 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 that occur during cleanup are always ignored; see the documentation for object.__del__() :

Warning : due to unstable circumstances in which __del__() calls methods, exceptions that occur during their execution are ignored, and instead a warning is displayed instead of sys.stderr .

The solution is to eliminate the exceptions that occur when cleaning the generator, or to eliminate the exception by explicitly closing the generator:

 >>> co = mycoroutine() >>> co.next() >>> try: ... co.close() ... except ValueError: ... pass ... >>> del co >>> # No exception was raised ... 

You can also catch the GeneratorExit exception and do some cleanup at this 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 generator.close() documentation :

If the generator function then raises StopIteration (by exiting from the normal state or because it is already closed) or GeneratorExit (if you do not catch the exception), close will return to its caller. If the generator gives a value, then a RuntimeError is expressed. If the generator raises any other exception, it applies to the caller.

+9
source

Source: https://habr.com/ru/post/953239/


All Articles