python-peps/pep-3152/index.html

267 lines
18 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 3152 Cofunctions | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-3152/">
<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 3152 Cofunctions | peps.python.org'>
<meta property="og:description" content="A syntax is proposed for defining and calling a special type of generator called a cofunction. It is designed to provide a streamlined way of writing generator-based coroutines, and allow the early detection of certain kinds of error that are easily ...">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-3152/">
<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="A syntax is proposed for defining and calling a special type of generator called a cofunction. It is designed to provide a streamlined way of writing generator-based coroutines, and allow the early detection of certain kinds of error that are easily ...">
<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 3152</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 3152 Cofunctions</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Gregory Ewing &lt;greg.ewing&#32;&#97;t&#32;canterbury.ac.nz&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</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">13-Feb-2009</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.3</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="#abstract">Abstract</a><ul>
<li><a class="reference internal" href="#rejection">Rejection</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#cofunction-definitions">Cofunction definitions</a></li>
<li><a class="reference internal" href="#cocalls">Cocalls</a></li>
<li><a class="reference internal" href="#new-builtins-attributes-and-c-api-functions">New builtins, attributes and C API functions</a></li>
</ul>
</li>
<li><a class="reference internal" href="#motivation-and-rationale">Motivation and Rationale</a></li>
<li><a class="reference internal" href="#prototype-implementation">Prototype Implementation</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>A syntax is proposed for defining and calling a special type of
generator called a cofunction. It is designed to provide a
streamlined way of writing generator-based coroutines, and allow the
early detection of certain kinds of error that are easily made when
writing such code, which otherwise tend to cause hard-to-diagnose
symptoms.</p>
<p>This proposal builds on the yield from mechanism described in PEP
380, and describes some of the semantics of cofunctions in terms of
it. However, it would be possible to define and implement cofunctions
independently of <a class="pep reference internal" href="../pep-0380/" title="PEP 380 Syntax for Delegating to a Subgenerator">PEP 380</a> if so desired.</p>
<section id="rejection">
<h3><a class="toc-backref" href="#rejection" role="doc-backlink">Rejection</a></h3>
<p>See <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2015-April/139503.html">https://mail.python.org/pipermail/python-dev/2015-April/139503.html</a></p>
</section>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<section id="cofunction-definitions">
<h3><a class="toc-backref" href="#cofunction-definitions" role="doc-backlink">Cofunction definitions</a></h3>
<p>A new keyword <code class="docutils literal notranslate"><span class="pre">codef</span></code> is introduced which is used in place of
<code class="docutils literal notranslate"><span class="pre">def</span></code> to define a cofunction. A cofunction is a special kind of
generator having the following characteristics:</p>
<ol class="arabic simple">
<li>A cofunction is always a generator, even if it does not contain any
<code class="docutils literal notranslate"><span class="pre">yield</span></code> or <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> expressions.</li>
<li>A cofunction cannot be called the same way as an ordinary function.
An exception is raised if an ordinary call to a cofunction is
attempted.</li>
</ol>
</section>
<section id="cocalls">
<h3><a class="toc-backref" href="#cocalls" role="doc-backlink">Cocalls</a></h3>
<p>Calls from one cofunction to another are made by marking the call with
a new keyword <code class="docutils literal notranslate"><span class="pre">cocall</span></code>. The expression</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cocall</span> <span class="n">f</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">kwds</span><span class="p">)</span>
</pre></div>
</div>
<p>is semantically equivalent to</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">yield from</span> <span class="n">f</span><span class="o">.</span><span class="n">__cocall__</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">kwds</span><span class="p">)</span>
</pre></div>
</div>
<p>except that the object returned by __cocall__ is expected to be an
iterator, so the step of calling iter() on it is skipped.</p>
<p>The full syntax of a cocall expression is described by the following
grammar lines:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">atom</span><span class="p">:</span> <span class="n">cocall</span> <span class="o">|</span> <span class="o">&lt;</span><span class="n">existing</span> <span class="n">alternatives</span> <span class="k">for</span> <span class="n">atom</span><span class="o">&gt;</span>
<span class="n">cocall</span><span class="p">:</span> <span class="s1">&#39;cocall&#39;</span> <span class="n">atom</span> <span class="n">cotrailer</span><span class="o">*</span> <span class="s1">&#39;(&#39;</span> <span class="p">[</span><span class="n">arglist</span><span class="p">]</span> <span class="s1">&#39;)&#39;</span>
<span class="n">cotrailer</span><span class="p">:</span> <span class="s1">&#39;[&#39;</span> <span class="n">subscriptlist</span> <span class="s1">&#39;]&#39;</span> <span class="o">|</span> <span class="s1">&#39;.&#39;</span> <span class="n">NAME</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">cocall</span></code> keyword is syntactically valid only inside a
cofunction. A SyntaxError will result if it is used in any other
context.</p>
<p>Objects which implement __cocall__ are expected to return an object
obeying the iterator protocol. Cofunctions respond to __cocall__ the
same way as ordinary generator functions respond to __call__, i.e. by
returning a generator-iterator.</p>
<p>Certain objects that wrap other callable objects, notably bound
methods, will be given __cocall__ implementations that delegate to the
underlying object.</p>
</section>
<section id="new-builtins-attributes-and-c-api-functions">
<h3><a class="toc-backref" href="#new-builtins-attributes-and-c-api-functions" role="doc-backlink">New builtins, attributes and C API functions</a></h3>
<p>To facilitate interfacing cofunctions with non-coroutine code, there will
be a built-in function <code class="docutils literal notranslate"><span class="pre">costart</span></code> whose definition is equivalent to</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">costart</span><span class="p">(</span><span class="n">obj</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">kwds</span><span class="p">):</span>
<span class="k">return</span> <span class="n">obj</span><span class="o">.</span><span class="n">__cocall__</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">kwds</span><span class="p">)</span>
</pre></div>
</div>
<p>There will also be a corresponding C API function</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span> <span class="o">*</span><span class="n">PyObject_CoCall</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">obj</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span>
</pre></div>
</div>
<p>It is left unspecified for now whether a cofunction is a distinct type
of object or, like a generator function, is simply a specially-marked
function instance. If the latter, a read-only boolean attribute
<code class="docutils literal notranslate"><span class="pre">__iscofunction__</span></code> should be provided to allow testing whether a
given function object is a cofunction.</p>
</section>
</section>
<section id="motivation-and-rationale">
<h2><a class="toc-backref" href="#motivation-and-rationale" role="doc-backlink">Motivation and Rationale</a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> syntax is reasonably self-explanatory when used for
the purpose of delegating part of the work of a generator to another
function. It can also be used to good effect in the implementation of
generator-based coroutines, but it reads somewhat awkwardly when used
for that purpose, and tends to obscure the true intent of the code.</p>
<p>Furthermore, using generators as coroutines is somewhat error-prone.
If one forgets to use <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> when it should have been used, or
uses it when it shouldnt have, the symptoms that result can be
obscure and confusing.</p>
<p>Finally, sometimes there is a need for a function to be a coroutine
even though it does not yield anything, and in these cases it is
necessary to resort to kludges such as <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">0:</span> <span class="pre">yield</span></code> to force it to
be a generator.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">codef</span></code> and <code class="docutils literal notranslate"><span class="pre">cocall</span></code> constructs address the first issue by
making the syntax directly reflect the intent, that is, that the
function forms part of a coroutine.</p>
<p>The second issue is addressed by making it impossible to mix coroutine
and non-coroutine code in ways that dont make sense. If the rules
are violated, an exception is raised that points out exactly what and
where the problem is.</p>
<p>Lastly, the need for dummy yields is eliminated by making the form of
definition determine whether the function is a coroutine, rather than
what it contains.</p>
</section>
<section id="prototype-implementation">
<h2><a class="toc-backref" href="#prototype-implementation" role="doc-backlink">Prototype Implementation</a></h2>
<p>An implementation in the form of patches to Python 3.1.2 can be found
here:</p>
<p><a class="reference external" href="http://www.cosc.canterbury.ac.nz/greg.ewing/python/generators/cofunctions.html">http://www.cosc.canterbury.ac.nz/greg.ewing/python/generators/cofunctions.html</a></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-3152.rst">https://github.com/python/peps/blob/main/peps/pep-3152.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3152.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="#abstract">Abstract</a><ul>
<li><a class="reference internal" href="#rejection">Rejection</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#cofunction-definitions">Cofunction definitions</a></li>
<li><a class="reference internal" href="#cocalls">Cocalls</a></li>
<li><a class="reference internal" href="#new-builtins-attributes-and-c-api-functions">New builtins, attributes and C API functions</a></li>
</ul>
</li>
<li><a class="reference internal" href="#motivation-and-rationale">Motivation and Rationale</a></li>
<li><a class="reference internal" href="#prototype-implementation">Prototype Implementation</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-3152.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>