[Python-Dev] GeneratorExit is unintuitive and uneccessary

Igor Bukanov igor.bukanov at gmail.com
Wed Aug 23 16:06:01 CEST 2006


On 8/23/06, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Simpler is in the eye of the beholder - the current close() merely uses
> throw() to raise a particular kind of exception 'asynchronously' (which is
> already a familiar concept due to KeyboardInterrupt). What you're suggesting
> is a completely new flow control concept that doesn't exist anywhere else in
> the language.

Yes, this is a new feature, but IMO the extra complexity it brings to
the implementation is worth simplifications for the user.

>
> I suggested during the PEP 352 discussions that GeneratorExit should inherit
> directly from BaseException, so that the fix to your example would be to
> replace the bare "except:" with "except Exception:"

That is, the idea was to make writing code that catches GeneratorExit
difficult, right? But then note that if the code never catches
GeneratorExit, then throwing GeneratorExit after the yield is exactly
equivalent to just returning after the yield. In either case only
finally blocks would be executed and close then would ignore
GeneratorExit or StopIteration exceptions.

So this proposal is just an extension of the idea "it should be
difficult to use catch to ignore GeneratorExit" to simpler "No catch
can catch GeneratorExit".

> (because it can swallow
> KeyboardInterrupt the version you posted is buggy regardless of how g.close()
> works).

So there are 4 kinds of exceptions now in Python:

1. Normal exceptions that are OK to catch and ignore.
2. Interrupts like KeyboardInterrupt that can be caught and ignored,
but this is not recommended and it is easy to avoid catching them
accidentally.
3. Interrupts like GeneratorExit that can be caught and ignored, but
this is not recommended and where one has to write a lot of code to
avoid catching them in a generic catch block.
4. Control transfer "exceptions" like break and continue across
finally blocks. With enough efforts one can catch and ignore them, but
then one know what he is doing:

for i in range(3):
  print "i:", i
  try:
    try:
      break
    finally:
      raise Exception
  except Exception:
    print "Ignoring break"

print "Done"

Ideally it would be nice to merge 2-3-4 into a single class of special
exceptions where the normal catch statement never sees them and extra
efforts are necessary to ignore them, but with this proposal at least
the list would not contain the item 3.

Please also note that these comments are born after playing with
generators in JS 1.7, the next JavaScript that Firefox 2.0 would
implement. The current JS implementation tries to follow PEP 352, but
since the only catch available in JS1.7 is just catch-all as before,
the problems with accidentally catching GeneratorExit are much more
visible in JS [1]. Thus changing close in JS to just return after
yield would address the issues nicely but perhaps this can help Python
users as well.

Regards, Igor

[1]  https://bugzilla.mozilla.org/show_bug.cgi?id=349331


More information about the Python-Dev mailing list