PEP 342: Fix misc. typos and grammar abuses I committed while short of

sleep.  :)
This commit is contained in:
Phillip J. Eby 2005-06-26 15:20:53 +00:00
parent 197f9dcbbc
commit c97e46d034
1 changed files with 40 additions and 37 deletions

View File

@ -38,58 +38,58 @@ Motivation
try/finally blocks, and therefore make it difficult for an aborted
coroutine to clean up after itself.
Generators also cannot yield control while other functions are
executing, unless those functions are also expressed as generators,
and the outer generator is written to yield in response to values
yielded by the inner generator, which complicates the implementation
of even relatively simple use cases like asynchronous
Also, generators cannot yield control while other functions are
executing, unless those functions are themselves expressed as
generators, and the outer generator is written to yield in response
to values yielded by the inner generator. This complicates the
implementation of even relatively simple use cases like asynchronous
communications, because calling any functions either requires the
generator to "block" (i.e. be unable to yield control), or else a
lot of boilerplate looping code around every needed function call.
lot of boilerplate looping code must be added around every needed
function call.
However, if it were possible to pass values or exceptions into a
However, if it were possible to pass values or exceptions *into* a
generator at the point where it was suspended, a simple co-routine
scheduler or "trampoline function" would let coroutines "call" each
other without blocking -- a tremendous boon for asynchronous
applications. Such applications could then write co-routines to
do non-blocking socket I/O by yielding control to an I/O scheduler
until data has been sent or becomes available. Meanwhile, code that
performs the I/O would simply do something like:
performs the I/O would simply do something like this:
data = (yield nonblocking_read(my_socket, nbytes))
In order to pause execution until the nonblocking_read() coroutine
in order to pause execution until the nonblocking_read() coroutine
produced a value.
In other words, with a few relatively minor enhancements to the
language and the implementation of the generator-iterator type,
Python will be able to support writing asynchronous applications
without needing to write entire applications as a series of
callbacks, and without requiring the use resource-intensive threads
language and to the implementation of the generator-iterator type,
Python will be able to support performing asynchronous operations
without needing to write the entire application as a series of
callbacks, and without requiring the use of resource-intensive threads
for programs that need hundreds or even thousands of co-operatively
multitasking pseudothreads. In a sense, these enhancements will
give Python many of the benefits of the Stackless Python fork,
multitasking pseudothreads. Thus, these enhancements will give
standard Python many of the benefits of the Stackless Python fork,
without requiring any significant modification to the CPython core
or its APIs. In addition, these enhancements should be readily
implementable by any Python implementation (such as Jython) that
already supports generators.
Specification Summary
By adding a few simple methods to the generator-iterator type, and
with two minor syntax adjustments, Python developers will be able
to use generator functions to implement co-routines and other forms
of co-operative multitasking. These method and adjustments are:
of co-operative multitasking. These methods and adjustments are:
1. Redefine "yield" to be an expression, rather than a statement.
The current yield statement would become a yield expression
whose value is thrown away. A yield expression's value is
None if the generator is resumed by a normal next() call.
None whenever the generator is resumed by a normal next() call.
2. Add a new send() method for generator-iterators, which resumes
the generator and "sends" a value that becomes the result of the
current "yield expression". The send() method returns the next
current yield-expression. The send() method returns the next
value yielded by the generator, or raises StopIteration if the
generator exits without yielding another value.
@ -99,7 +99,7 @@ Specification Summary
StopIteration if the generator exits without yielding another
value. (If the generator does not catch the passed-in exception,
or raises a different exception, then that exception propagates
to the caller.
to the caller.)
4. Add a close() method for generator-iterators, which raises
GeneratorExit at the point where the generator was paused. If
@ -111,12 +111,12 @@ Specification Summary
close() does nothing if the generator has already exited due to
an exception or normal exit.
5. Adding support to ensure that close() is called when a generator
5. Add support to ensure that close() is called when a generator
iterator is garbage-collected.
6. Allowing "yield" to be used in try/finally blocks, since garbage
collection or an explicit close() call allows the finally clause
to execute.
6. Allow "yield" to be used in try/finally blocks, since garbage
collection or an explicit close() call would now allow the
finally clause to execute.
A prototype patch implementing all of these changes against the
current Python CVS HEAD is available as SourceForge patch #1223381
@ -140,14 +140,14 @@ Specification: Sending Values into Generators
calling send() with a non-None argument is prohibited when the
generator iterator has just started, and a TypeError is raised if
this occurs (presumably due to a logic error of some kind). Thus,
before you can communicate with a coroutine you must call first
call next() or send(None) to advance its execution to its first
yield expression.
before you can communicate with a coroutine you must first call
next() or send(None) to advance its execution to the first yield
expression.
As with the next() method, the send() method returns the next value
yielded by the generator-iterator, or raises StopIteration if the
generator exits normally, or has already exited. If the generator
raises an exception, it is propagated to send()'s caller.
raises an uncaught exception, it is propagated to send()'s caller.
New syntax: Yield Expressions
@ -242,16 +242,16 @@ Specification: Exceptions and Cleanup
was executed at the suspension point. The type argument must
not be None, and the type and value must be compatible. If the
value is not an instance of the type, a new exception instance
is created, with the value passed in as argument(s), following
the same rules that the raise statement uses to create an
exception instance. The traceback, if supplied, must be a valid
Python traceback object, or a TypeError occurs.
is created using the value, following the same rules that the raise
statement uses to create an exception instance. The traceback, if
supplied, must be a valid Python traceback object, or a TypeError
occurs.
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.
(or just not catching it) or by raising StopIteration.
New generator method: close()
@ -283,13 +283,16 @@ Specification: Exceptions and Cleanup
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.
is passed to the generator as an argument (e.g., if an object has
a method that's a generator, and keeps a reference to a running
iterator created by that method). Neither of these cases
are very likely given the typical patterns of generator use.
Also, in the CPython implementation of this PEP, the frame object
used by the generator should be released whenever its execution is
@ -375,12 +378,12 @@ Examples
import collections
class Trampoline:
"""Manage communications between coroutines until
"""Manage communications between coroutines"""
running = False
def __init__(self):
self.queue = collections.deque
self.queue = collections.deque()
def add(self, coroutine):
"""Request that a coroutine be executed"""