[Python-Dev] Combining the best of PEP 288 and PEP 325: generatorexceptions and cleanup

Phillip J. Eby pje at telecommunity.com
Wed May 18 20:32:58 CEST 2005


At 01:24 PM 5/18/2005 -0400, Raymond Hettinger wrote:
> > - g.throw(type, value, traceback) causes the specified exception to be
> > thrown at the place where the generator g is currently suspended.
>
>Are the value and traceback arguments optional as they are with the
>current raise statement?  If they are optional, what would the default
>be?  I think the preferred choice is to have the call to the throw
>method be the anchor point.  That makes sense in a traceback so you can
>see who threw the exception.
>
>The alternative is to have the generator resumption point be the anchor.
>That is closer to the notion that throw(ex) is equivalent to a "raise
>ex" following the last yield.   This probably isn't the way to go but
>the PEP should address it explicitly.

My use case for throw() calls for the latter option; i.e., the exception is 
raised by the yield expression at the resumption point.  Keep in mind that 
if the exception passes out of the generator, the throw() call will show in 
the traceback anyway.  It's unlikely the generator itself will inspect the 
traceback and need to see the throw() call as if it were nested.


> > If the generator raises another exception (this includes
> > the StopIteration produced when it returns) that exception is raised
> > by the throw. In summary, throw() behaves like next() except it raises
> > an exception at the place of the yield.
>
>The parallel to next() makes this easy to understand, learn, and
>implement.  However, there are some disadvantages to passing through a
>StopIteration.  It means that throw() calls usually need to be wrapped
>in a try/except or that a generator's exception handler would terminate
>with a "yield None" where a "return" would be more natural.  As a
>example, it is a bit painful to simulate the effects of g.close() using
>g.throw(GeneratorExit).

I don't see this as a big problem, personally, but that's because all of my 
use cases for throw() will be using only one piece of code that calls 
throw(), and that code will be overall simplified by the availability of 
throw().

It's also easy to write a wrapper for control-flow "signals" of the kind 
you used in PEP 288:

     def send(gen, *exc):
         try:
             return gen.throw(*exc)
         except StopIteration:
             pass



More information about the Python-Dev mailing list