Greg Ewing wrote:
Nick Coghlan wrote:
Well, in theory people are meant to be writing "except Exception:" rather than using a bare except or catching BaseException - that's a big part of the reason SystemExit, KeyboardInterrupt and GeneratorExit *aren't* Exception subclasses.
Yes, it probably isn't something people will do very often. But as long as GeneratorExit is documented as an official part of the language, we need to explain how we're dealing with it. As my last (flawed) example shows, it is easy to accidently convert the GeneratorExit (along with any other uncaught exception) to a StopIteration if you are using a finally clause. You don't need to explicitly catch anything. Code that does this should be considered broken. Not so much because it is swallowing GeneratorExit, but because it swallows *any* exception. I don't think we should add special cases to the yield-from semantics to cater for broken code.
I even think it might have been a mistake in PEP 342 to let close swallow StopIteration. It might have been better if a throw to an already-closed generator just raised the thrown exception, and close only swallowed GeneratorExit. That way, you would quickly discover that the generator was swallowing exceptions because a call to close would cause a StopIteration. With that definition, we would consider any generator that did not (under normal conditions) raise GeneratorExit when thrown a GeneratorExit to be broken. Had that been the definition, I think we would long ago have agreed to let yield-from treat GeneratorExit like any other exception. Unfortunately that is not how things work, and I am afraid that changing it would "break" too much code. I put "break" in quotes, because I think most such code is already broken in the sense that it can swallow exceptions that it shouldn't, such as KeyboardInterrupt and SystemExit. Even without changing throw and close, I still think we should forward GeneratorExit like any other exception, and not do anything special to reraise it or call close on the subiterator. To me that sounds like the cleaner solution, and it is what the inlining principle suggests. It is unfortunate that you have to be a bit more careful about not swallowing GeneratorExit, but I think that care is needed anyway to avoid swallowing other exceptions as well.
BTW, how official *is* it meant to be? There seems to be very little said about it in either the Language or Library Reference.
The Library Ref says it's the "exception raised when a generator's close() method is called". The Language Ref says that the close() method "allows finally clauses to run", but doesn't say how that is accomplished.
And I can't find throw() mentioned anywhere!
All the generator methods are described here: http://docs.python.org/reference/expressions.html#yield-expressions - Jacob