In article <mailman.999833409.3011.python-list at python.org>,
Tim Peters <tim.one at home.com> wrote:
>[Aahz]
>>>> 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.
Gotcha. So after the generator gets suspended, the call chain in using
generators always refers to the frame in which g.next() executes. I
think adding that statement to the PEP would be helpful in reducing
confusion.
To expand on this a bit, essentially a generator lives in two contexts:
* In the first context, a generator-iterator is created, but no code
within the generator is executed. This means that it is functionally
impossible to raise an exception at this point (aside from the usual
NameError if the generator object isn't found). The generator is
created in a suspended state; if g.next() is never called, the generator
will never do anything.
* In the second context, g.next() activates the generator, which runs
until it hits a yield, a return, or raises an exception. Whichever
frame calls g.next() is considered the parent frame. Using a single
generator-iterator object across multiple threads is a Bad Idea (with
the usual caveats about careful locking).
(Yes, I think all of this is in the PEP, but I think the PEP could use a
clear summary like this. Or I suppose I could try writing up something
for Fred to use in the docs -- I don't see anything in the dev docs
about generators.)
--
--- Aahz <*> (Copyright 2001 by aahz at pobox.com)
Hugs and backrubs -- I break Rule 6 http://www.rahul.net/aahz/
Androgynous poly kinky vanilla queer het Pythonista
"Plus ca change, plus c'est la meme chose."