[Python-ideas] Yield-From: Finalization guarantees
jh at improva.dk
Wed Apr 1 17:39:34 CEST 2009
Nick Coghlan wrote:
> Jacob Holm wrote:
>> Explicitly catching GeneratorExit and then returning is a valid use
>> today that I wouldn't consider suspect. Catching GeneratorExit and then
>> exiting the except block by other means than a raise or return is
>> suspect, but has valid uses.
> What are these valid uses? The PEP 342 definition made some sense
> originally when GeneratorExit was a subclass of Exception and hence easy
> to suppress accidentally, but I have serious doubts about the validity
> of trapping it and turning it into StopIteration now that it has been
> moved out to inherit directly from BaseException.
When catching and returning, the control flow is different than if you
were catching and raising. Also using "return" more clearly signals the
intent to leave the generator than "raise". Even with GeneratorExit
inheriting directly from BaseException, it is still easier to intercept
an exception than a return.
The use for catching and exiting the block normally is to share some
code between the cases. Of course you need to be careful when you do
that, but it can save some duplication.
Both these uses are valid in the sense that the generators work as
advertised and follow the rules of finalization as defined by PEP 342.
I don't think a proposal for changing close to not accept StopIteration
is going to fly.
> Regardless, unless Greg goes out of his way to change the meaning of
> close() in the PEP, GeneratorReturn will escape from close() (since that
> only traps StopIteration). That means you'll be able to catch that
> exception directly if you really want to, and if you don't it will
> bubble up out of the original close() call that was made on the
> outermost generator.
Hmm. I had almost forgotten about the separate GeneratorReturn
exception. It would be good to see how that changes things. So far I
consider it a needless complication, but I would like to read a version
of the PEP that include it to see how bad it is.
As for GeneratorReturn not being caught by close(), I find it really
strange if returning a non-None value as a response to GeneratorExit
makes close() raise a GeneratorReturn. Whereas returning None makes
close finish without an exception. If you think returning a non-None
value is an error, we should make it a (subclass of) RuntimeError rather
than a GeneratorReturn to clearly indicate this.
I am strongly in favor of changing close to return the value rather than
letting the GeneratorReturn pass through or raising a RuntimeError. I
think the "averager" example I just gave is a good (but simplistic)
example of the kind of code I would consider using coroutines for. The
need to catch an exception would make that code a lot less readable, not
to mention slower.
I am not about to write a separate PEP for this, but I would consider
"return from generator" plus "close returns value returned from
generator" to be a worthwhile addition in itself.
More information about the Python-ideas