[Python-Dev] Combining the best of PEP 288 and PEP 325: generator exceptions and cleanup
Guido van Rossum
gvanrossum at gmail.com
Wed May 18 18:39:11 CEST 2005
I believe that in the discussion about PEP 343 vs. Nick's PEP 3XX
awaiting PEP moderator approval I believe?) the main difference is
that Nick proposes a way to inject an exception into a generator; and
I've said a few times that I like that idea.
I'd like to propose to make that a separate PEP, which can combine
elements of PEP 288 and PEP 325. Summary:
- g.throw(type, value, traceback) causes the specified exception to be
thrown at the place where the generator g is currently suspended. If
the generator catches the exception and yields another value, that is
the return value of g.throw(). If it doesn't catch the exception, the
throw() appears to raise the same exception passed it (it "falls
through"). 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. If the generator is already in
the closed state, throw() just raises the exception it was passed
without going through the generator.
- There's a new exception, GeneratorExit, which can be thrown to cause
a generator to clean up. A generator should not yield a value in
response to this exception.
- g.close() throws a GeneratorExit exception in the generator, and
catches it (so g.close() itself does not raise an exception).
g.close() is idempotent -- if the generator is already closed, it is a
no-op. If the generator, against the rules, yields another value, it
is nevertheless marked closed.
- When a generator is GC'ed, its close() method is called (which is a
no-op if it is already closed).
That's it! With this, we can write the decorator from Nick's PEP 3XX
and the generator examples in PEP 343 can be rewritten to have a
try/finally clause around the yield statement.
Oh, somewhere it should be stated that yield without an expression is
equivalent to yield None. PEP 342 ("continue EXPR") already implies
that, so we don't have to write a separate PEP for it. I also propose
to go with the alternative in PEP 342 of using next() rather than
__next__() -- generators will have methods next(), throw(), and
--Guido van Rossum (home page: http://www.python.org/~guido/)
More information about the Python-Dev