Generators and exceptions (was Re: Stackless Python and Python 2.x)

Tim Peters tim.one at home.com
Thu Sep 6 23:29:04 EDT 2001


[Aahz]
> Okay, I've re-read PEP 255, and I'm still not clear on what happens with
> the following code:
>
> def a():
>     yield 1
>     raise "foo"
>     yield 2
>     return

It's impossible to get to the "yield 2", of course.

> def b():
>     return a()

When called, returns a generator (iterator) for the generator (function) a.

> g = b()

The point to the b function isn't clear to me.  Everything works the same if
you get rid of b and replace the line above with

g = a()

> g.next()

a is resumed, it executes the "yield 1" and suspends, returning 1 as the
value of the "g.next()" expression.  Note that the b function has nothing to
do with this:  a generator always returns to its immediate *invoker*, not
necessarily to the function that created the iterator.  After "g = b()", b's
role in this is finished.

> g.next()

a is resumed, it executes the 'raise "foo"', and (from PEP 255)

    If an unhandled exception-- including, but not limited to,
    StopIteration --is raised by, or passes through, a generator
    function, then the exception is passed on to the caller in the
    usual way,

Again, b is long gone, and is in no way "the caller" of g.next().  So the
result of this is:

Traceback (most recent call last):
  File "aahz.py", line 14, in ?
    g.next()
  File "aahz.py", line 5, in a
    raise "foo"
foo

Your code ends there, but the PEP doesn't <wink>:

    and subsequent attempts to resume the generator function raise
    StopIteration.  In other words, an unhandled exception terminates
    a generator's useful life.

So if we change your last two lines from

    g.next()
    g.next()

to

    print g.next() # 1
    try:
        print g.next() # 2
    except "foo":  # dangerous -- exceptions are compared by identity,
                   # not value, and this works by accident
        print "OK, foo was raised"
    print g.next() # 3

then the output becomes

1
OK, foo was raised
Traceback (most recent call last):
  File "aahz.py", line 19, in ?
    print g.next() # 3
StopIteration

An unhandled exception kills all flavors of functions, generators included.

BTW, I suspect your view of generators is too complex, not too simple.  So
try to unlearn something that isn't true <wink>.





More information about the Python-list mailing list