peps/pep-0342/index.html

704 lines
64 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 342 Coroutines via Enhanced Generators | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0342/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 342 Coroutines via Enhanced Generators | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0342/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 342</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 342 Coroutines via Enhanced Generators</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Guido van Rossum, Phillip J. Eby</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">10-May-2005</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.5</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even"><p></p></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#specification-summary">Specification Summary</a></li>
<li><a class="reference internal" href="#specification-sending-values-into-generators">Specification: Sending Values into Generators</a><ul>
<li><a class="reference internal" href="#new-generator-method-send-value">New generator method: <code class="docutils literal notranslate"><span class="pre">send(value)</span></code></a></li>
<li><a class="reference internal" href="#new-syntax-yield-expressions">New syntax: Yield Expressions</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification-exceptions-and-cleanup">Specification: Exceptions and Cleanup</a><ul>
<li><a class="reference internal" href="#new-syntax-yield-allowed-inside-try-finally">New syntax: <code class="docutils literal notranslate"><span class="pre">yield</span></code> allowed inside <code class="docutils literal notranslate"><span class="pre">try-finally</span></code></a></li>
<li><a class="reference internal" href="#new-generator-method-throw-type-value-none-traceback-none">New generator method: <code class="docutils literal notranslate"><span class="pre">throw(type,</span> <span class="pre">value=None,</span> <span class="pre">traceback=None)</span></code></a></li>
<li><a class="reference internal" href="#new-standard-exception-generatorexit">New standard exception: <code class="docutils literal notranslate"><span class="pre">GeneratorExit</span></code></a></li>
<li><a class="reference internal" href="#new-generator-method-close">New generator method: <code class="docutils literal notranslate"><span class="pre">close()</span></code></a></li>
<li><a class="reference internal" href="#new-generator-method-del">New generator method: __del__()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#optional-extensions">Optional Extensions</a><ul>
<li><a class="reference internal" href="#the-extended-continue-statement">The Extended <code class="docutils literal notranslate"><span class="pre">continue</span></code> Statement</a></li>
</ul>
</li>
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
<li><a class="reference internal" href="#examples">Examples</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="introduction">
<h2><a class="toc-backref" href="#introduction" role="doc-backlink">Introduction</a></h2>
<p>This PEP proposes some enhancements to the API and syntax of generators, to
make them usable as simple coroutines. It is basically a combination of ideas
from these two PEPs, which may be considered redundant if this PEP is
accepted:</p>
<ul class="simple">
<li><a class="pep reference internal" href="../pep-0288/" title="PEP 288 Generators Attributes and Exceptions">PEP 288</a>, Generators Attributes and Exceptions. The current PEP covers its
second half, generator exceptions (in fact the <code class="docutils literal notranslate"><span class="pre">throw()</span></code> method name was
taken from <a class="pep reference internal" href="../pep-0288/" title="PEP 288 Generators Attributes and Exceptions">PEP 288</a>). <a class="pep reference internal" href="../pep-0342/" title="PEP 342 Coroutines via Enhanced Generators">PEP 342</a> replaces generator attributes, however, with a
concept from an earlier revision of <a class="pep reference internal" href="../pep-0288/" title="PEP 288 Generators Attributes and Exceptions">PEP 288</a>, the <em>yield expression</em>.</li>
<li><a class="pep reference internal" href="../pep-0325/" title="PEP 325 Resource-Release Support for Generators">PEP 325</a>, Resource-Release Support for Generators. <a class="pep reference internal" href="../pep-0342/" title="PEP 342 Coroutines via Enhanced Generators">PEP 342</a> ties up a few
loose ends in the <a class="pep reference internal" href="../pep-0325/" title="PEP 325 Resource-Release Support for Generators">PEP 325</a> spec, to make it suitable for actual
implementation.</li>
</ul>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>Coroutines are a natural way of expressing many algorithms, such as
simulations, games, asynchronous I/O, and other forms of event-driven
programming or co-operative multitasking. Pythons generator functions are
almost coroutines but not quite in that they allow pausing execution to
produce a value, but do not provide for values or exceptions to be passed in
when execution resumes. They also do not allow execution to be paused within
the <code class="docutils literal notranslate"><span class="pre">try</span></code> portion of <code class="docutils literal notranslate"><span class="pre">try/finally</span></code> blocks, and therefore make it difficult
for an aborted coroutine to clean up after itself.</p>
<p>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 <em>block</em> (i.e. be unable to yield control), or else a
lot of boilerplate looping code must be added around every needed function
call.</p>
<p>However, if it were possible to pass values or exceptions <em>into</em> a generator at
the point where it was suspended, a simple co-routine scheduler or <em>trampoline
function</em> would let coroutines <em>call</em> 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 this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">data</span> <span class="o">=</span> <span class="p">(</span><span class="k">yield</span> <span class="n">nonblocking_read</span><span class="p">(</span><span class="n">my_socket</span><span class="p">,</span> <span class="n">nbytes</span><span class="p">))</span>
</pre></div>
</div>
<p>in order to pause execution until the <code class="docutils literal notranslate"><span class="pre">nonblocking_read()</span></code> coroutine produced
a value.</p>
<p>In other words, with a few relatively minor enhancements to the 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. 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.</p>
</section>
<section id="specification-summary">
<h2><a class="toc-backref" href="#specification-summary" role="doc-backlink">Specification Summary</a></h2>
<p>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 methods and adjustments are:</p>
<ol class="arabic simple">
<li>Redefine <code class="docutils literal notranslate"><span class="pre">yield</span></code> to be an expression, rather than a statement. The current
yield statement would become a yield expression whose value is thrown away.
A yield expressions value is <code class="docutils literal notranslate"><span class="pre">None</span></code> whenever the generator is resumed by
a normal <code class="docutils literal notranslate"><span class="pre">next()</span></code> call.</li>
<li>Add a new <code class="docutils literal notranslate"><span class="pre">send()</span></code> method for generator-iterators, which resumes the
generator and <em>sends</em> a value that becomes the result of the current
yield-expression. The <code class="docutils literal notranslate"><span class="pre">send()</span></code> method returns the next value yielded by
the generator, or raises <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> if the generator exits without
yielding another value.</li>
<li>Add a new <code class="docutils literal notranslate"><span class="pre">throw()</span></code> method for generator-iterators, which raises an
exception at the point where the generator was paused, and which returns the
next value yielded by the generator, raising <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> 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.)</li>
<li>Add a <code class="docutils literal notranslate"><span class="pre">close()</span></code> method for generator-iterators, which raises
<code class="docutils literal notranslate"><span class="pre">GeneratorExit</span></code> at the point where the generator was paused. If the
generator then raises <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> (by exiting normally, or due to
already being closed) or <code class="docutils literal notranslate"><span class="pre">GeneratorExit</span></code> (by not catching the exception),
<code class="docutils literal notranslate"><span class="pre">close()</span></code> returns to its caller. If the generator yields a value, a
<code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code> is raised. If the generator raises any other exception, it
is propagated to the caller. <code class="docutils literal notranslate"><span class="pre">close()</span></code> does nothing if the generator has
already exited due to an exception or normal exit.</li>
<li>Add support to ensure that <code class="docutils literal notranslate"><span class="pre">close()</span></code> is called when a generator iterator
is garbage-collected.</li>
<li>Allow <code class="docutils literal notranslate"><span class="pre">yield</span></code> to be used in <code class="docutils literal notranslate"><span class="pre">try/finally</span></code> blocks, since garbage
collection or an explicit <code class="docutils literal notranslate"><span class="pre">close()</span></code> call would now allow the <code class="docutils literal notranslate"><span class="pre">finally</span></code>
clause to execute.</li>
</ol>
<p>A prototype patch implementing all of these changes against the current Python
CVS HEAD is available as SourceForge patch #1223381
(<a class="reference external" href="https://bugs.python.org/issue1223381">https://bugs.python.org/issue1223381</a>).</p>
</section>
<section id="specification-sending-values-into-generators">
<h2><a class="toc-backref" href="#specification-sending-values-into-generators" role="doc-backlink">Specification: Sending Values into Generators</a></h2>
<section id="new-generator-method-send-value">
<h3><a class="toc-backref" href="#new-generator-method-send-value" role="doc-backlink">New generator method: <code class="docutils literal notranslate"><span class="pre">send(value)</span></code></a></h3>
<p>A new method for generator-iterators is proposed, called <code class="docutils literal notranslate"><span class="pre">send()</span></code>. It
takes exactly one argument, which is the value that should be <em>sent in</em> to
the generator. Calling <code class="docutils literal notranslate"><span class="pre">send(None)</span></code> is exactly equivalent to calling a
generators <code class="docutils literal notranslate"><span class="pre">next()</span></code> method. Calling <code class="docutils literal notranslate"><span class="pre">send()</span></code> with any other value is
the same, except that the value produced by the generators current
yield expression will be different.</p>
<p>Because generator-iterators begin execution at the top of the generators
function body, there is no yield expression to receive a value when the
generator has just been created. Therefore, calling <code class="docutils literal notranslate"><span class="pre">send()</span></code> with a
non-<code class="docutils literal notranslate"><span class="pre">None</span></code> argument is prohibited when the generator iterator has just
started, and a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> is raised if this occurs (presumably due to a
logic error of some kind). Thus, before you can communicate with a
coroutine you must first call <code class="docutils literal notranslate"><span class="pre">next()</span></code> or <code class="docutils literal notranslate"><span class="pre">send(None)</span></code> to advance its
execution to the first yield expression.</p>
<p>As with the <code class="docutils literal notranslate"><span class="pre">next()</span></code> method, the <code class="docutils literal notranslate"><span class="pre">send()</span></code> method returns the next value
yielded by the generator-iterator, or raises <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> if the
generator exits normally, or has already exited. If the generator raises an
uncaught exception, it is propagated to <code class="docutils literal notranslate"><span class="pre">send()</span></code>s caller.</p>
</section>
<section id="new-syntax-yield-expressions">
<h3><a class="toc-backref" href="#new-syntax-yield-expressions" role="doc-backlink">New syntax: Yield Expressions</a></h3>
<p>The yield-statement will be allowed to be used on the right-hand side of an
assignment; in that case it is referred to as yield-expression. The value
of this yield-expression is <code class="docutils literal notranslate"><span class="pre">None</span></code> unless <code class="docutils literal notranslate"><span class="pre">send()</span></code> was called with a
non-<code class="docutils literal notranslate"><span class="pre">None</span></code> argument; see below.</p>
<p>A yield-expression must always be parenthesized except when it occurs at the
top-level expression on the right-hand side of an assignment. So</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">=</span> <span class="k">yield</span> <span class="mi">42</span>
<span class="n">x</span> <span class="o">=</span> <span class="k">yield</span>
<span class="n">x</span> <span class="o">=</span> <span class="mi">12</span> <span class="o">+</span> <span class="p">(</span><span class="k">yield</span> <span class="mi">42</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="mi">12</span> <span class="o">+</span> <span class="p">(</span><span class="k">yield</span><span class="p">)</span>
<span class="n">foo</span><span class="p">(</span><span class="k">yield</span> <span class="mi">42</span><span class="p">)</span>
<span class="n">foo</span><span class="p">(</span><span class="k">yield</span><span class="p">)</span>
</pre></div>
</div>
<p>are all legal, but</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">=</span> <span class="mi">12</span> <span class="o">+</span> <span class="k">yield</span> <span class="mi">42</span>
<span class="n">x</span> <span class="o">=</span> <span class="mi">12</span> <span class="o">+</span> <span class="k">yield</span>
<span class="n">foo</span><span class="p">(</span><span class="k">yield</span> <span class="mi">42</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span>
<span class="n">foo</span><span class="p">(</span><span class="k">yield</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span>
</pre></div>
</div>
<p>are all illegal. (Some of the edge cases are motivated by the current
legality of <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">12,</span> <span class="pre">42</span></code>.)</p>
<p>Note that a yield-statement or yield-expression without an expression is now
legal. This makes sense: when the information flow in the <code class="docutils literal notranslate"><span class="pre">next()</span></code> call
is reversed, it should be possible to yield without passing an explicit
value (<code class="docutils literal notranslate"><span class="pre">yield</span></code> is of course equivalent to <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">None</span></code>).</p>
<p>When <code class="docutils literal notranslate"><span class="pre">send(value)</span></code> is called, the yield-expression that it resumes will
return the passed-in value. When <code class="docutils literal notranslate"><span class="pre">next()</span></code> is called, the resumed
yield-expression will return <code class="docutils literal notranslate"><span class="pre">None</span></code>. If the yield-expression is a
yield-statement, this returned value is ignored, similar to ignoring the
value returned by a function call used as a statement.</p>
<p>In effect, a yield-expression is like an inverted function call; the
argument to yield is in fact returned (yielded) from the currently executing
function, and the <em>return value</em> of yield is the argument passed in via
<code class="docutils literal notranslate"><span class="pre">send()</span></code>.</p>
<p>Note: the syntactic extensions to yield make its use very similar to that in
Ruby. This is intentional. Do note that in Python the block passes a value
to the generator using <code class="docutils literal notranslate"><span class="pre">send(EXPR)</span></code> rather than <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">EXPR</span></code>, and the
underlying mechanism whereby control is passed between the generator and the
block is completely different. Blocks in Python are not compiled into
thunks; rather, <code class="docutils literal notranslate"><span class="pre">yield</span></code> suspends execution of the generators frame. Some
edge cases work differently; in Python, you cannot save the block for later
use, and you cannot test whether there is a block or not. (XXX - this stuff
about blocks seems out of place now, perhaps Guido can edit to clarify.)</p>
</section>
</section>
<section id="specification-exceptions-and-cleanup">
<h2><a class="toc-backref" href="#specification-exceptions-and-cleanup" role="doc-backlink">Specification: Exceptions and Cleanup</a></h2>
<p>Let a generator object be the iterator produced by calling a generator
function. Below, <em>g</em> always refers to a generator object.</p>
<section id="new-syntax-yield-allowed-inside-try-finally">
<h3><a class="toc-backref" href="#new-syntax-yield-allowed-inside-try-finally" role="doc-backlink">New syntax: <code class="docutils literal notranslate"><span class="pre">yield</span></code> allowed inside <code class="docutils literal notranslate"><span class="pre">try-finally</span></code></a></h3>
<p>The syntax for generator functions is extended to allow a yield-statement
inside a <code class="docutils literal notranslate"><span class="pre">try-finally</span></code> statement.</p>
</section>
<section id="new-generator-method-throw-type-value-none-traceback-none">
<h3><a class="toc-backref" href="#new-generator-method-throw-type-value-none-traceback-none" role="doc-backlink">New generator method: <code class="docutils literal notranslate"><span class="pre">throw(type,</span> <span class="pre">value=None,</span> <span class="pre">traceback=None)</span></code></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">g.throw(type,</span> <span class="pre">value,</span> <span class="pre">traceback)</span></code> causes the specified exception to be
thrown at the point where the generator <em>g</em> is currently suspended (i.e. at
a yield-statement, or at the start of its function body if <code class="docutils literal notranslate"><span class="pre">next()</span></code> has
not been called yet). If the generator catches the exception and yields
another value, that is the return value of <code class="docutils literal notranslate"><span class="pre">g.throw()</span></code>. If it doesnt
catch the exception, the <code class="docutils literal notranslate"><span class="pre">throw()</span></code> appears to raise the same exception
passed it (it <em>falls through</em>). If the generator raises another exception
(this includes the <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> produced when it returns) that
exception is raised by the <code class="docutils literal notranslate"><span class="pre">throw()</span></code> call. In summary, <code class="docutils literal notranslate"><span class="pre">throw()</span></code>
behaves like <code class="docutils literal notranslate"><span class="pre">next()</span></code> or <code class="docutils literal notranslate"><span class="pre">send()</span></code>, except it raises an exception at the
suspension point. If the generator is already in the closed state,
<code class="docutils literal notranslate"><span class="pre">throw()</span></code> just raises the exception it was passed without executing any of
the generators code.</p>
<p>The effect of raising the exception is exactly as if the statement:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">raise</span> <span class="nb">type</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">traceback</span>
</pre></div>
</div>
<p>was executed at the suspension point. The type argument must not be
<code class="docutils literal notranslate"><span class="pre">None</span></code>, and the type and value must be compatible. If the value is not an
instance of the type, a new exception instance is created using the value,
following the same rules that the <code class="docutils literal notranslate"><span class="pre">raise</span></code> statement uses to create an
exception instance. The traceback, if supplied, must be a valid Python
traceback object, or a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> occurs.</p>
<p>Note: The name of the <code class="docutils literal notranslate"><span class="pre">throw()</span></code> method was selected for several reasons.
<code class="docutils literal notranslate"><span class="pre">Raise</span></code> is a keyword and so cannot be used as a method name. Unlike
<code class="docutils literal notranslate"><span class="pre">raise</span></code> (which immediately raises an exception from the current execution
point), <code class="docutils literal notranslate"><span class="pre">throw()</span></code> first resumes the generator, and only then raises the
exception. The word <em>throw</em> is suggestive of putting the exception in
another location, and is already associated with exceptions in other
languages.</p>
<p>Alternative method names were considered: <code class="docutils literal notranslate"><span class="pre">resolve()</span></code>, <code class="docutils literal notranslate"><span class="pre">signal()</span></code>,
<code class="docutils literal notranslate"><span class="pre">genraise()</span></code>, <code class="docutils literal notranslate"><span class="pre">raiseinto()</span></code>, and <code class="docutils literal notranslate"><span class="pre">flush()</span></code>. None of these seem to fit
as well as <code class="docutils literal notranslate"><span class="pre">throw()</span></code>.</p>
</section>
<section id="new-standard-exception-generatorexit">
<h3><a class="toc-backref" href="#new-standard-exception-generatorexit" role="doc-backlink">New standard exception: <code class="docutils literal notranslate"><span class="pre">GeneratorExit</span></code></a></h3>
<p>A new standard exception is defined, <code class="docutils literal notranslate"><span class="pre">GeneratorExit</span></code>, inheriting from
<code class="docutils literal notranslate"><span class="pre">Exception</span></code>. A generator should handle this by re-raising it (or just not
catching it) or by raising <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code>.</p>
</section>
<section id="new-generator-method-close">
<h3><a class="toc-backref" href="#new-generator-method-close" role="doc-backlink">New generator method: <code class="docutils literal notranslate"><span class="pre">close()</span></code></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">g.close()</span></code> is defined by the following pseudo-code:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">throw</span><span class="p">(</span><span class="ne">GeneratorExit</span><span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">GeneratorExit</span><span class="p">,</span> <span class="ne">StopIteration</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;generator ignored GeneratorExit&quot;</span><span class="p">)</span>
<span class="c1"># Other exceptions are not caught</span>
</pre></div>
</div>
</section>
<section id="new-generator-method-del">
<h3><a class="toc-backref" href="#new-generator-method-del" role="doc-backlink">New generator method: __del__()</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">g.__del__()</span></code> is a wrapper for <code class="docutils literal notranslate"><span class="pre">g.close()</span></code>. This will be called when
the generator object is garbage-collected (in CPython, this is when its
reference count goes to zero). If <code class="docutils literal notranslate"><span class="pre">close()</span></code> raises an exception, a
traceback for the exception is printed to <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> 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
<code class="docutils literal notranslate"><span class="pre">__del__()</span></code> methods on class instances.</p>
<p>If the generator object participates in a cycle, <code class="docutils literal notranslate"><span class="pre">g.__del__()</span></code> may not be
called. This is the behavior of CPythons current garbage collector. The
reason for the restriction is that the GC code needs to <em>break</em> 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 <em>hanging off</em> a cycle are not subject to this
restriction.</p>
<p>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 frames <code class="docutils literal notranslate"><span class="pre">f_globals</span></code> 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 (e.g., if an
object has a method thats 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.</p>
<p>Also, in the CPython implementation of this PEP, the frame object used by
the generator should be released whenever its execution is terminated due to
an error or normal exit. This will ensure that generators that cannot be
resumed do not remain part of an uncollectable reference cycle. This allows
other code to potentially use <code class="docutils literal notranslate"><span class="pre">close()</span></code> in a <code class="docutils literal notranslate"><span class="pre">try/finally</span></code> or <code class="docutils literal notranslate"><span class="pre">with</span></code>
block (per <a class="pep reference internal" href="../pep-0343/" title="PEP 343 The “with” Statement">PEP 343</a>) to ensure that a given generator is properly finalized.</p>
</section>
</section>
<section id="optional-extensions">
<h2><a class="toc-backref" href="#optional-extensions" role="doc-backlink">Optional Extensions</a></h2>
<section id="the-extended-continue-statement">
<h3><a class="toc-backref" href="#the-extended-continue-statement" role="doc-backlink">The Extended <code class="docutils literal notranslate"><span class="pre">continue</span></code> Statement</a></h3>
<p>An earlier draft of this PEP proposed a new <code class="docutils literal notranslate"><span class="pre">continue</span> <span class="pre">EXPR</span></code> syntax for use
in for-loops (carried over from <a class="pep reference internal" href="../pep-0340/" title="PEP 340 Anonymous Block Statements">PEP 340</a>), that would pass the value of
<em>EXPR</em> into the iterator being looped over. This feature has been withdrawn
for the time being, because the scope of this PEP has been narrowed to focus
only on passing values into generator-iterators, and not other kinds of
iterators. It was also felt by some on the Python-Dev list that adding new
syntax for this particular feature would be premature at best.</p>
</section>
</section>
<section id="open-issues">
<h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2>
<p>Discussion on python-dev has revealed some open issues. I list them here, with
my preferred resolution and its motivation. The PEP as currently written
reflects this preferred resolution.</p>
<ol class="arabic">
<li>What exception should be raised by <code class="docutils literal notranslate"><span class="pre">close()</span></code> when the generator yields
another value as a response to the <code class="docutils literal notranslate"><span class="pre">GeneratorExit</span></code> exception?<p>I originally chose <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> because it represents gross misbehavior of
the generator function, which should be fixed by changing the code. But the
<code class="docutils literal notranslate"><span class="pre">with_template</span></code> decorator class in <a class="pep reference internal" href="../pep-0343/" title="PEP 343 The “with” Statement">PEP 343</a> uses <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code> for
similar offenses. Arguably they should all use the same exception. Id
rather not introduce a new exception class just for this purpose, since its
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 <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code>. There are some precedents
for that: its raised by the core Python code in situations where endless
recursion is detected, and for uninitialized objects (and for a variety of
miscellaneous conditions).</p>
</li>
<li>Oren Tirosh has proposed renaming the <code class="docutils literal notranslate"><span class="pre">send()</span></code> method to <code class="docutils literal notranslate"><span class="pre">feed()</span></code>, for
compatibility with the <em>consumer interface</em> (see
<a class="reference external" href="http://effbot.org/zone/consumer.htm">http://effbot.org/zone/consumer.htm</a> for the specification.)<p>However, looking more closely at the consumer interface, it seems that the
desired semantics for <code class="docutils literal notranslate"><span class="pre">feed()</span></code> are different than for <code class="docutils literal notranslate"><span class="pre">send()</span></code>, because
<code class="docutils literal notranslate"><span class="pre">send()</span></code> cant be meaningfully called on a just-started generator. Also,
the consumer interface as currently defined doesnt include handling for
<code class="docutils literal notranslate"><span class="pre">StopIteration</span></code>.</p>
<p>Therefore, it seems like it would probably be more useful to create a simple
decorator that wraps a generator function to make it conform to the consumer
interface. For example, it could <em>warm up</em> the generator with an initial
<code class="docutils literal notranslate"><span class="pre">next()</span></code> call, trap StopIteration, and perhaps even provide <code class="docutils literal notranslate"><span class="pre">reset()</span></code> by
re-invoking the generator function.</p>
</li>
</ol>
</section>
<section id="examples">
<h2><a class="toc-backref" href="#examples" role="doc-backlink">Examples</a></h2>
<ol class="arabic">
<li>A simple <em>consumer</em> decorator that makes a generator function automatically
advance to its first yield point when initially called:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">consumer</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="o">**</span><span class="n">kw</span><span class="p">):</span>
<span class="n">gen</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
<span class="n">gen</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="k">return</span> <span class="n">gen</span>
<span class="n">wrapper</span><span class="o">.</span><span class="vm">__name__</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="vm">__name__</span>
<span class="n">wrapper</span><span class="o">.</span><span class="vm">__dict__</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="vm">__dict__</span>
<span class="n">wrapper</span><span class="o">.</span><span class="vm">__doc__</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="vm">__doc__</span>
<span class="k">return</span> <span class="n">wrapper</span>
</pre></div>
</div>
</li>
<li>An example of using the <em>consumer</em> decorator to create a <em>reverse generator</em>
that receives images and creates thumbnail pages, sending them on to another
consumer. Functions like this can be chained together to form efficient
processing pipelines of <em>consumers</em> that each can have complex internal
state:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@consumer</span>
<span class="k">def</span> <span class="nf">thumbnail_pager</span><span class="p">(</span><span class="n">pagesize</span><span class="p">,</span> <span class="n">thumbsize</span><span class="p">,</span> <span class="n">destination</span><span class="p">):</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">page</span> <span class="o">=</span> <span class="n">new_image</span><span class="p">(</span><span class="n">pagesize</span><span class="p">)</span>
<span class="n">rows</span><span class="p">,</span> <span class="n">columns</span> <span class="o">=</span> <span class="n">pagesize</span> <span class="o">/</span> <span class="n">thumbsize</span>
<span class="n">pending</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">xrange</span><span class="p">(</span><span class="n">rows</span><span class="p">):</span>
<span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">xrange</span><span class="p">(</span><span class="n">columns</span><span class="p">):</span>
<span class="n">thumb</span> <span class="o">=</span> <span class="n">create_thumbnail</span><span class="p">((</span><span class="k">yield</span><span class="p">),</span> <span class="n">thumbsize</span><span class="p">)</span>
<span class="n">page</span><span class="o">.</span><span class="n">write</span><span class="p">(</span>
<span class="n">thumb</span><span class="p">,</span> <span class="n">col</span><span class="o">*</span><span class="n">thumbsize</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">row</span><span class="o">*</span><span class="n">thumbsize</span><span class="o">.</span><span class="n">y</span> <span class="p">)</span>
<span class="n">pending</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">except</span> <span class="ne">GeneratorExit</span><span class="p">:</span>
<span class="c1"># close() was called, so flush any pending output</span>
<span class="k">if</span> <span class="n">pending</span><span class="p">:</span>
<span class="n">destination</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">page</span><span class="p">)</span>
<span class="c1"># then close the downstream consumer, and exit</span>
<span class="n">destination</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">return</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># we finished a page full of thumbnails, so send it</span>
<span class="c1"># downstream and keep on looping</span>
<span class="n">destination</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">page</span><span class="p">)</span>
<span class="nd">@consumer</span>
<span class="k">def</span> <span class="nf">jpeg_writer</span><span class="p">(</span><span class="n">dirname</span><span class="p">):</span>
<span class="n">fileno</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dirname</span><span class="p">,</span><span class="s2">&quot;page</span><span class="si">%04d</span><span class="s2">.jpg&quot;</span> <span class="o">%</span> <span class="n">fileno</span><span class="p">)</span>
<span class="n">write_jpeg</span><span class="p">((</span><span class="k">yield</span><span class="p">),</span> <span class="n">filename</span><span class="p">)</span>
<span class="n">fileno</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="c1"># Put them together to make a function that makes thumbnail</span>
<span class="c1"># pages from a list of images and other parameters.</span>
<span class="c1">#</span>
<span class="k">def</span> <span class="nf">write_thumbnails</span><span class="p">(</span><span class="n">pagesize</span><span class="p">,</span> <span class="n">thumbsize</span><span class="p">,</span> <span class="n">images</span><span class="p">,</span> <span class="n">output_dir</span><span class="p">):</span>
<span class="n">pipeline</span> <span class="o">=</span> <span class="n">thumbnail_pager</span><span class="p">(</span>
<span class="n">pagesize</span><span class="p">,</span> <span class="n">thumbsize</span><span class="p">,</span> <span class="n">jpeg_writer</span><span class="p">(</span><span class="n">output_dir</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">image</span> <span class="ow">in</span> <span class="n">images</span><span class="p">:</span>
<span class="n">pipeline</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">image</span><span class="p">)</span>
<span class="n">pipeline</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
</li>
<li>A simple co-routine scheduler or <em>trampoline</em> that lets coroutines <em>call</em>
other coroutines by yielding the coroutine they wish to invoke. Any
non-generator value yielded by a coroutine is returned to the coroutine that
<em>called</em> the one yielding the value. Similarly, if a coroutine raises an
exception, the exception is propagated to its <em>caller</em>. In effect, this
example emulates simple tasklets as are used in Stackless Python, as long as
you use a yield expression to invoke routines that would otherwise <em>block</em>.
This is only a very simple example, and far more sophisticated schedulers
are possible. (For example, the existing GTasklet framework for Python
(<a class="reference external" href="http://www.gnome.org/~gjc/gtasklet/gtasklets.html">http://www.gnome.org/~gjc/gtasklet/gtasklets.html</a>) and the peak.events
framework (<a class="reference external" href="http://peak.telecommunity.com/">http://peak.telecommunity.com/</a>) already implement similar
scheduling capabilities, but must currently use awkward workarounds for the
inability to pass values or exceptions into generators.)<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">collections</span>
<span class="k">class</span> <span class="nc">Trampoline</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Manage communications between coroutines&quot;&quot;&quot;</span>
<span class="n">running</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">queue</span> <span class="o">=</span> <span class="n">collections</span><span class="o">.</span><span class="n">deque</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">coroutine</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Request that a coroutine be executed&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">schedule</span><span class="p">(</span><span class="n">coroutine</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">result</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">running</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">while</span> <span class="bp">self</span><span class="o">.</span><span class="n">running</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="p">:</span>
<span class="n">func</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="o">.</span><span class="n">popleft</span><span class="p">()</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">func</span><span class="p">()</span>
<span class="k">return</span> <span class="n">result</span>
<span class="k">finally</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">running</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">stop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">running</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">schedule</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">coroutine</span><span class="p">,</span> <span class="n">stack</span><span class="o">=</span><span class="p">(),</span> <span class="n">val</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="n">exc</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">resume</span><span class="p">():</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">val</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="n">exc</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">coroutine</span><span class="o">.</span><span class="n">throw</span><span class="p">(</span><span class="n">value</span><span class="p">,</span><span class="o">*</span><span class="n">exc</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">coroutine</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">if</span> <span class="n">stack</span><span class="p">:</span>
<span class="c1"># send the error back to the &quot;caller&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">schedule</span><span class="p">(</span>
<span class="n">stack</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">stack</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">*</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">()</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># Nothing left in this pseudothread to</span>
<span class="c1"># handle it, let it propagate to the</span>
<span class="c1"># run loop</span>
<span class="k">raise</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">types</span><span class="o">.</span><span class="n">GeneratorType</span><span class="p">):</span>
<span class="c1"># Yielded to a specific coroutine, push the</span>
<span class="c1"># current one on the stack, and call the new</span>
<span class="c1"># one with no args</span>
<span class="bp">self</span><span class="o">.</span><span class="n">schedule</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="p">(</span><span class="n">coroutine</span><span class="p">,</span><span class="n">stack</span><span class="p">))</span>
<span class="k">elif</span> <span class="n">stack</span><span class="p">:</span>
<span class="c1"># Yielded a result, pop the stack and send the</span>
<span class="c1"># value to the caller</span>
<span class="bp">self</span><span class="o">.</span><span class="n">schedule</span><span class="p">(</span><span class="n">stack</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">stack</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">value</span><span class="p">)</span>
<span class="c1"># else: this pseudothread has ended</span>
<span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">resume</span><span class="p">)</span>
</pre></div>
</div>
</li>
<li>A simple <em>echo</em> server, and code to run it using a trampoline (presumes the
existence of <code class="docutils literal notranslate"><span class="pre">nonblocking_read</span></code>, <code class="docutils literal notranslate"><span class="pre">nonblocking_write</span></code>, and other I/O
coroutines, that e.g. raise <code class="docutils literal notranslate"><span class="pre">ConnectionLost</span></code> if the connection is
closed):<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># coroutine function that echos data back on a connected</span>
<span class="c1"># socket</span>
<span class="c1">#</span>
<span class="k">def</span> <span class="nf">echo_handler</span><span class="p">(</span><span class="n">sock</span><span class="p">):</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">nonblocking_read</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
<span class="k">yield</span> <span class="n">nonblocking_write</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
<span class="k">except</span> <span class="n">ConnectionLost</span><span class="p">:</span>
<span class="k">pass</span> <span class="c1"># exit normally if connection lost</span>
<span class="c1"># coroutine function that listens for connections on a</span>
<span class="c1"># socket, and then launches a service &quot;handler&quot; coroutine</span>
<span class="c1"># to service the connection</span>
<span class="c1">#</span>
<span class="k">def</span> <span class="nf">listen_on</span><span class="p">(</span><span class="n">trampoline</span><span class="p">,</span> <span class="n">sock</span><span class="p">,</span> <span class="n">handler</span><span class="p">):</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="c1"># get the next incoming connection</span>
<span class="n">connected_socket</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">nonblocking_accept</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
<span class="c1"># start another coroutine to handle the connection</span>
<span class="n">trampoline</span><span class="o">.</span><span class="n">add</span><span class="p">(</span> <span class="n">handler</span><span class="p">(</span><span class="n">connected_socket</span><span class="p">)</span> <span class="p">)</span>
<span class="c1"># Create a scheduler to manage all our coroutines</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">Trampoline</span><span class="p">()</span>
<span class="c1"># Create a coroutine instance to run the echo_handler on</span>
<span class="c1"># incoming connections</span>
<span class="c1">#</span>
<span class="n">server</span> <span class="o">=</span> <span class="n">listen_on</span><span class="p">(</span>
<span class="n">t</span><span class="p">,</span> <span class="n">listening_socket</span><span class="p">(</span><span class="s2">&quot;localhost&quot;</span><span class="p">,</span><span class="s2">&quot;echo&quot;</span><span class="p">),</span> <span class="n">echo_handler</span>
<span class="p">)</span>
<span class="c1"># Add the coroutine to the scheduler</span>
<span class="n">t</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">server</span><span class="p">)</span>
<span class="c1"># loop forever, accepting connections and servicing them</span>
<span class="c1"># &quot;in parallel&quot;</span>
<span class="c1">#</span>
<span class="n">t</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</pre></div>
</div>
</li>
</ol>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>A prototype patch implementing all of the features described in this PEP is
available as SourceForge patch #1223381 (<a class="reference external" href="https://bugs.python.org/issue1223381">https://bugs.python.org/issue1223381</a>).</p>
<p>This patch was committed to CVS 01-02 August 2005.</p>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<p>Raymond Hettinger (<a class="pep reference internal" href="../pep-0288/" title="PEP 288 Generators Attributes and Exceptions">PEP 288</a>) and Samuele Pedroni (<a class="pep reference internal" href="../pep-0325/" title="PEP 325 Resource-Release Support for Generators">PEP 325</a>) first formally
proposed the ideas of communicating values or exceptions into generators, and
the ability to <em>close</em> generators. Timothy Delaney suggested the title of this
PEP, and Steven Bethard helped edit a previous version. See also the
Acknowledgements section of <a class="pep reference internal" href="../pep-0340/" title="PEP 340 Anonymous Block Statements">PEP 340</a>.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<p>TBD.</p>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0342.rst">https://github.com/python/peps/blob/main/peps/pep-0342.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0342.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#specification-summary">Specification Summary</a></li>
<li><a class="reference internal" href="#specification-sending-values-into-generators">Specification: Sending Values into Generators</a><ul>
<li><a class="reference internal" href="#new-generator-method-send-value">New generator method: <code class="docutils literal notranslate"><span class="pre">send(value)</span></code></a></li>
<li><a class="reference internal" href="#new-syntax-yield-expressions">New syntax: Yield Expressions</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification-exceptions-and-cleanup">Specification: Exceptions and Cleanup</a><ul>
<li><a class="reference internal" href="#new-syntax-yield-allowed-inside-try-finally">New syntax: <code class="docutils literal notranslate"><span class="pre">yield</span></code> allowed inside <code class="docutils literal notranslate"><span class="pre">try-finally</span></code></a></li>
<li><a class="reference internal" href="#new-generator-method-throw-type-value-none-traceback-none">New generator method: <code class="docutils literal notranslate"><span class="pre">throw(type,</span> <span class="pre">value=None,</span> <span class="pre">traceback=None)</span></code></a></li>
<li><a class="reference internal" href="#new-standard-exception-generatorexit">New standard exception: <code class="docutils literal notranslate"><span class="pre">GeneratorExit</span></code></a></li>
<li><a class="reference internal" href="#new-generator-method-close">New generator method: <code class="docutils literal notranslate"><span class="pre">close()</span></code></a></li>
<li><a class="reference internal" href="#new-generator-method-del">New generator method: __del__()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#optional-extensions">Optional Extensions</a><ul>
<li><a class="reference internal" href="#the-extended-continue-statement">The Extended <code class="docutils literal notranslate"><span class="pre">continue</span></code> Statement</a></li>
</ul>
</li>
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
<li><a class="reference internal" href="#examples">Examples</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0342.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>