PEP 343: Remove functionality now covered under PEP 342.
This commit is contained in:
parent
f00c8f7acb
commit
5b3f4e8ce0
121
pep-0343.txt
121
pep-0343.txt
|
@ -26,19 +26,9 @@ Introduction
|
|||
If this PEP is approved, the following PEPs will be rejected due
|
||||
to overlap:
|
||||
|
||||
- PEP 288, Generators Attributes and Exceptions. The current PEP
|
||||
covers its second half, generator exceptions (in fact the
|
||||
throw() method name was taken from this PEP). I'm not in favor
|
||||
of generator attributes, since they can easily be handled by
|
||||
making the generator a method or by passing a mutable argument.
|
||||
|
||||
- PEP 310, Reliable Acquisition/Release Pairs. This is the
|
||||
original with-statement proposal.
|
||||
|
||||
- PEP 325, Resource-Release Support for Generators. The current
|
||||
PEP covers this (in fact the close() method name was taken from
|
||||
this PEP).
|
||||
|
||||
- PEP 319, Python Synchronize/Asynchronize Block. Its use cases
|
||||
can be covered by the current PEP by providing suitable
|
||||
with-statement controllers: for 'synchronize' we can use the
|
||||
|
@ -262,91 +252,11 @@ Specification: The 'with' Statement
|
|||
non-local goto should be considered unexceptional for the purposes
|
||||
of a database transaction roll-back decision.
|
||||
|
||||
Specification: Generator Enhancements
|
||||
|
||||
Let a generator object be the iterator produced by calling a
|
||||
generator function. Below, 'g' always refers to a generator
|
||||
object.
|
||||
|
||||
New syntax: yield allowed inside try-finally
|
||||
|
||||
The syntax for generator functions is extended to allow a
|
||||
yield-statement inside a try-finally statement.
|
||||
|
||||
New generator method: throw(type, value=None, traceback=None)
|
||||
|
||||
g.throw(type, value, traceback) causes the specified exception to
|
||||
be thrown at the point where the generator g is currently
|
||||
suspended (i.e. at a yield-statement, or at the start of its
|
||||
function body if next() has not been called yet). 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() call. In summary, throw()
|
||||
behaves like next() except it raises an exception at the
|
||||
suspension point. If the generator is already in the closed
|
||||
state, throw() just raises the exception it was passed without
|
||||
executing any of the generator's code.
|
||||
|
||||
The effect of raising the exception is exactly as if the
|
||||
statement:
|
||||
|
||||
raise type, value, traceback
|
||||
|
||||
was executed at the suspension point. The type argument should
|
||||
not be None.
|
||||
|
||||
New standard exception: GeneratorExit
|
||||
|
||||
A new standard exception is defined, GeneratorExit, inheriting
|
||||
from Exception. A generator should handle this by re-raising it
|
||||
or by raising StopIteration.
|
||||
|
||||
New generator method: close()
|
||||
|
||||
g.close() is defined by the following pseudo-code:
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self.throw(GeneratorExit, GeneratorExit(), None)
|
||||
except (GeneratorExit, StopIteration):
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError("generator ignored GeneratorExit")
|
||||
# Other exceptions are not caught
|
||||
|
||||
New generator method: __del__()
|
||||
|
||||
g.__del__() is an alias for g.close(). This will be called when
|
||||
the generator object is garbage-collected (in CPython, this is
|
||||
when its reference count goes to zero). If close() raises an
|
||||
exception, a traceback for the exception is printed to sys.stderr
|
||||
and further ignored; it is not propagated back to the place that
|
||||
triggered the garbage collection. This is consistent with the
|
||||
handling of exceptions in __del__() methods on class instances.
|
||||
|
||||
If the generator object participates in a cycle, g.__del__() may
|
||||
not be called. This is the behavior of CPython's current garbage
|
||||
collector. The reason for the restriction is that the GC code
|
||||
needs to "break" a cycle at an arbitrary point in order to collect
|
||||
it, and from then on no Python code should be allowed to see the
|
||||
objects that formed the cycle, as they may be in an invalid state.
|
||||
Objects "hanging off" a cycle are not subject to this restriction.
|
||||
Note that it is unlikely to see a generator object participate in
|
||||
a cycle in practice. However, storing a generator object in a
|
||||
global variable creates a cycle via the generator frame's
|
||||
f_globals pointer. Another way to create a cycle would be to
|
||||
store a reference to the generator object in a data structure that
|
||||
is passed to the generator as an argument. Neither of these cases
|
||||
are very likely given the typical pattern of generator use.
|
||||
|
||||
Generator Decorator
|
||||
|
||||
It is possible to write a decorator that makes it possible to use
|
||||
a generator that yields exactly once to control a with-statement.
|
||||
Here's a sketch of such a decorator:
|
||||
If PEP 342 is accepted, it will be possible to write a decorator
|
||||
that makes it possible to use a generator that yields exactly once
|
||||
to control a with-statement. Here's a sketch of such a decorator:
|
||||
|
||||
class Wrapper(object):
|
||||
|
||||
|
@ -431,28 +341,9 @@ Open Issues
|
|||
them here, with my preferred resolution and its motivation. The
|
||||
PEP as currently written reflects this preferred resolution.
|
||||
|
||||
1. What exception should be raised by close() when the generator
|
||||
yields another value as a response to the GeneratorExit
|
||||
exception?
|
||||
|
||||
I originally chose TypeError because it represents gross
|
||||
misbehavior of the generator function, which should be fixed by
|
||||
changing the code. But the with_template decorator class uses
|
||||
RuntimeError for similar offenses. Arguably they should all
|
||||
use the same exception. I'd rather not introduce a new
|
||||
exception class just for this purpose, since it's not an
|
||||
exception that I want people to catch: I want it to turn into a
|
||||
traceback which is seen by the programmer who then fixes the
|
||||
code. So now I believe they should both raise RuntimeError.
|
||||
There are some precedents for that: it's raised by the core
|
||||
Python code in situations where endless recursion is detected,
|
||||
and for uninitialized objects (and for a variety of
|
||||
miscellaneous conditions).
|
||||
|
||||
2. Both the generator close() method and the __exit__() method of
|
||||
the with_template decorator class catch StopIteration and
|
||||
consider it equivalent to re-raising the exception passed to
|
||||
throw(). Is allowing StopIteration right here?
|
||||
1. The __exit__() method of the with_template decorator class catches
|
||||
StopIteration and considers it equivalent to re-raising the exception
|
||||
passed to throw(). Is allowing StopIteration right here?
|
||||
|
||||
This is so that a generator doing cleanup depending on the
|
||||
exception thrown (like the transactional() example below) can
|
||||
|
|
Loading…
Reference in New Issue