[Python-Dev] GeneratorExit is unintuitive and uneccessary
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/
4. 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:
4. 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