summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew M. Kuchling <amk@amk.ca>2005-08-27 18:45:47 (GMT)
committerAndrew M. Kuchling <amk@amk.ca>2005-08-27 18:45:47 (GMT)
commit0738206e79d700121e7a1850651de18413afdc14 (patch)
treedc658a2b3b645daede766088bb18cfc6a4743c65
parent9a19e5cce61c48a6092d8d1448d70072c724529c (diff)
downloadcpython-0738206e79d700121e7a1850651de18413afdc14.zip
cpython-0738206e79d700121e7a1850651de18413afdc14.tar.gz
cpython-0738206e79d700121e7a1850651de18413afdc14.tar.bz2
Write section on PEP 342
-rw-r--r--Doc/whatsnew/whatsnew25.tex122
1 files changed, 112 insertions, 10 deletions
diff --git a/Doc/whatsnew/whatsnew25.tex b/Doc/whatsnew/whatsnew25.tex
index 2d9ea6b..74cbf76 100644
--- a/Doc/whatsnew/whatsnew25.tex
+++ b/Doc/whatsnew/whatsnew25.tex
@@ -117,12 +117,10 @@ implemented by Richard Jones and Fred Drake.}
As introduced in Python 2.3, generators only produce output; once a
generator's code was invoked to create an iterator, there's no way to
pass new parameters into the function when its execution is resumed.
-(Well, you could make the generator's code look at a global
-variable and modify the global value, but this is an unreliable hack
-that doesn't work if you have multiple instances of the same generator
-alive at the same time.)
-
-Python 2.5 adds the ability to pass values \emph{into} a generator.
+Hackish solutions to this include making the generator's code look at
+a global variable and then changing the global variable's value, or
+passing in some mutable object that callers then modify. Python
+2.5 adds the ability to pass values \emph{into} a generator.
To refresh your memory of basic generators, here's a simple example:
@@ -134,16 +132,120 @@ def counter (maximum):
i += 1
\end{verbatim}
-On executing the \
-When you call \code{counter(10)}, the result is an
+When you call \code{counter(10)}, the result is an iterator that
+returns the values from 0 up to 9. On encountering the
+\keyword{yield} statement, the iterator returns the provided value and
+suspends the function's execution, preserving the local variables.
+Execution resumes on the following call to the iterator's
+\method{next()} method, picking up after the \keyword{yield}.
+
+In Python 2.3, \keyword{yield} was a statement; it didn't return any
+value. In 2.5, \keyword{yield} is now an expression, returning a
+value that can be assigned to a variable or otherwise operated on:
+
+\begin{verbatim}
+val = (yield i)
+\end{verbatim}
+
+I recommend that you always put parentheses around a \keyword{yield}
+expression when you're doing something with the returned value, as in
+the above example. The parentheses aren't always necessary, but it's
+easier to always add them instead of having to remember when they're
+needed. The exact rules are that a \keyword{yield}-expression must
+always be parenthesized except when it occurs at the top-level
+expression on the right-hand side of an assignment, meaning
+you can to write \code{val = yield i} but \code{val = (yield i) + 12}.
+
+Values are sent into a generator by calling its
+\method{send(\var{value})} method. The generator's code is then
+resumed and the \keyword{yield} expression produces \var{value}.
+If the regular \method{next()} method is called, the \keyword{yield}
+returns \constant{None}.
+
+Here's the previous example, modified to allow changing the value of
+the internal counter.
+
+\begin{verbatim}
+def counter (maximum):
+ i = 0
+ while i < maximum:
+ val = (yield i)
+ # If value provided, change counter
+ if val is not None:
+ i = val
+ else:
+ i += 1
+\end{verbatim}
+
+And here's an example of changing the counter:
+
+\begin{verbatim}
+>>> it = counter(10)
+>>> print it.next()
+0
+>>> print it.next()
+1
+>>> print it.send(8)
+8
+>>> print it.next()
+9
+>>> print it.next()
+Traceback (most recent call last):
+ File ``t.py'', line 15, in ?
+ print it.next()
+StopIteration
+
+Because \keyword{yield} will often be returning \constant{None},
+you shouldn't just use its value in expressions unless you're sure
+that only the \method{send()} method will be used.
+
+There are two other new methods on generators in addition to
+\method{send()}:
+
+\begin{itemize}
+
+ \item \method{throw(\var{type}, \var{value}=None,
+ \var{traceback}=None)} is used to raise an exception inside the
+ generator; the exception is raised by the \keyword{yield} expression
+ where the generator's execution is paused.
-XXX write this section
+ \item \method{close()} raises a new \exception{GeneratorExit}
+ exception inside the generator to terminate the iteration.
+ On receiving this
+ exception, the generator's code must either raise
+ \exception{GeneratorExit} or \exception{StopIteration}; catching the
+ exception and doing anything else is illegal and will trigger
+ a \exception{RuntimeError}. \method{close()} will also be called by
+ Python's garbage collection when the generator is garbage-collected.
+ If you need to run cleanup code in case of a \exception{GeneratorExit},
+ I suggest using a \code{try: ... finally:} suite instead of
+ catching \exception{GeneratorExit}.
+
+\end{itemize}
+
+The cumulative effect of these changes is to turn generators from
+one-way producers of information into both producers and consumers.
+Generators also become \emph{coroutines}, a more generalized form of
+subroutines; subroutines are entered at one point and exited at
+another point (the top of the function, and a \keyword{return
+statement}), but coroutines can be entered, exited, and resumed at
+many different points (the \keyword{yield} statements).science term
+
+
\begin{seealso}
\seepep{342}{Coroutines via Enhanced Generators}{PEP written by
Guido van Rossum and Phillip J. Eby;
-implemented by Phillip J. Eby.}
+implemented by Phillip J. Eby. Includes examples of
+some fancier uses of generators as coroutines.}
+
+\seeurl{http://en.wikipedia.org/wiki/Coroutine}{The Wikipedia entry for
+coroutines.}
+
+\seeurl{http://www.sidhe.org/~dan/blog/archives/000178.html}{An
+explanation of coroutines from a Perl point of view, written by Dan
+Sugalski.}
\end{seealso}