[Python-Dev] GeneratorExit is unintuitive and uneccessary (original) (raw)

Igor Bukanov igor.bukanov at gmail.com
Tue Aug 22 15:17:20 CEST 2006


Consider the following example:

for i in range(3): try: print i break except: print "Unexpected exception!" finally: print "Finally"

When executed, it naturally prints 0 Finally since break does not use exceptions to transfer the control and as such can not be stopped using catch-all exception handler.

Now consider a similar example using generators:

def gen(): for i in range(3): try: yield i except: print "Unexpected exception!" finally: print "Finally"

for i in gen(): print i break

This example prints: 0 Unexpected exception! Finally Exception exceptions.RuntimeError: 'generator ignored GeneratorExit' in <generator object at 0xb7daaa8c> ignored

Suddenly with generators a program can mess with control transfer since it uses explicit GeneratorExit which can be caught and ignored. This is unintuitive IMO.

This example also suggests how to fix generators. One just need to change the close method so it would cause return executed right after the yield instead of throw.

I.e. replace the current text from http://www.python.org/dev/peps/pep-0342/

  1. Add a close() method for generator-iterators, which raises GeneratorExit at the point where the generator was paused. If the generator then raises StopIteration (by exiting normally, or due to already being closed) or GeneratorExit (by not catching the exception), close() returns to its caller. If the generator yields a value, a RuntimeError is raised. If the generator raises any other exception, it is propagated to the caller. close() does nothing if the generator has already exited due to an exception or normal exit.

by simpler one:

  1. Add a close() method for generator-iterators, which executes normal return at the point where the generator was paused. If the generator then raises StopIteration (by exiting normally, or due to already being closed), close() returns to its caller. If the generator yields a value, a RuntimeError is raised. If the generator raises any other exception, it is propagated to the caller. close() does nothing if the generator has already exited due to an exception or normal exit.

This not only fixes the above discrepancy between normal flow control and generators, removes GeneratorExit and simplifies the generator protocol, but also bring a new feature allowing to have easy to grasp feature table of the iterator methods:

next: continue after yield throw: raise after yield close: return after yield

Regards, Igor



More information about the Python-Dev mailing list