[Python-ideas] Yield-From: Finalization guarantees

Jacob Holm 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.

- Jacob

More information about the Python-ideas mailing list