mirror of https://github.com/python/peps
1587 lines
143 KiB
HTML
1587 lines
143 KiB
HTML
|
||
<!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 492 – Coroutines with async and await syntax | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0492/">
|
||
<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 492 – Coroutines with async and await syntax | peps.python.org'>
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0492/">
|
||
<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> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 492</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 492 – Coroutines with async and await syntax</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Yury Selivanov <yury at edgedb.com></dd>
|
||
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
|
||
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/python-dev@python.org/">Python-Dev list</a></dd>
|
||
<dt class="field-odd">Status<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
|
||
<dt class="field-even">Type<span class="colon">:</span></dt>
|
||
<dd class="field-even"><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-odd">Created<span class="colon">:</span></dt>
|
||
<dd class="field-odd">09-Apr-2015</dd>
|
||
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-even">3.5</dd>
|
||
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-odd">17-Apr-2015, 21-Apr-2015, 27-Apr-2015, 29-Apr-2015, 05-May-2015</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></li>
|
||
<li><a class="reference internal" href="#api-design-and-implementation-revisions">API Design and Implementation Revisions</a></li>
|
||
<li><a class="reference internal" href="#rationale-and-goals">Rationale and Goals</a></li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#new-coroutine-declaration-syntax">New Coroutine Declaration Syntax</a></li>
|
||
<li><a class="reference internal" href="#types-coroutine">types.coroutine()</a></li>
|
||
<li><a class="reference internal" href="#await-expression">Await Expression</a><ul>
|
||
<li><a class="reference internal" href="#updated-operator-precedence-table">Updated operator precedence table</a></li>
|
||
<li><a class="reference internal" href="#examples-of-await-expressions">Examples of “await” expressions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#asynchronous-context-managers-and-async-with">Asynchronous Context Managers and “async with”</a><ul>
|
||
<li><a class="reference internal" href="#new-syntax">New Syntax</a></li>
|
||
<li><a class="reference internal" href="#example">Example</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#asynchronous-iterators-and-async-for">Asynchronous Iterators and “async for”</a><ul>
|
||
<li><a class="reference internal" href="#id12">New Syntax</a></li>
|
||
<li><a class="reference internal" href="#example-1">Example 1</a></li>
|
||
<li><a class="reference internal" href="#example-2">Example 2</a></li>
|
||
<li><a class="reference internal" href="#why-stopasynciteration">Why StopAsyncIteration?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#coroutine-objects">Coroutine objects</a><ul>
|
||
<li><a class="reference internal" href="#differences-from-generators">Differences from generators</a></li>
|
||
<li><a class="reference internal" href="#coroutine-object-methods">Coroutine object methods</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#debugging-features">Debugging Features</a></li>
|
||
<li><a class="reference internal" href="#new-standard-library-functions">New Standard Library Functions</a></li>
|
||
<li><a class="reference internal" href="#new-abstract-base-classes">New Abstract Base Classes</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#glossary">Glossary</a></li>
|
||
<li><a class="reference internal" href="#transition-plan">Transition Plan</a><ul>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
|
||
<li><a class="reference internal" href="#asyncio">asyncio</a></li>
|
||
<li><a class="reference internal" href="#asyncio-migration-strategy">asyncio migration strategy</a></li>
|
||
<li><a class="reference internal" href="#async-await-in-cpython-code-base">async/await in CPython code base</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#grammar-updates">Grammar Updates</a></li>
|
||
<li><a class="reference internal" href="#deprecation-plans">Deprecation Plans</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#design-considerations">Design Considerations</a><ul>
|
||
<li><a class="reference internal" href="#pep-3152">PEP 3152</a></li>
|
||
<li><a class="reference internal" href="#coroutine-generators">Coroutine-generators</a></li>
|
||
<li><a class="reference internal" href="#why-async-and-await-keywords">Why “async” and “await” keywords</a></li>
|
||
<li><a class="reference internal" href="#why-aiter-does-not-return-an-awaitable">Why “__aiter__” does not return an awaitable</a></li>
|
||
<li><a class="reference internal" href="#importance-of-async-keyword">Importance of “async” keyword</a></li>
|
||
<li><a class="reference internal" href="#why-async-def">Why “async def”</a></li>
|
||
<li><a class="reference internal" href="#why-not-await-for-and-await-with">Why not “await for” and “await with”</a></li>
|
||
<li><a class="reference internal" href="#why-async-def-and-not-def-async">Why “async def” and not “def async”</a></li>
|
||
<li><a class="reference internal" href="#why-not-a-future-import">Why not a __future__ import</a></li>
|
||
<li><a class="reference internal" href="#why-magic-methods-start-with-a">Why magic methods start with “a”</a></li>
|
||
<li><a class="reference internal" href="#why-not-reuse-existing-magic-names">Why not reuse existing magic names</a></li>
|
||
<li><a class="reference internal" href="#why-not-reuse-existing-for-and-with-statements">Why not reuse existing “for” and “with” statements</a></li>
|
||
<li><a class="reference internal" href="#comprehensions">Comprehensions</a></li>
|
||
<li><a class="reference internal" href="#async-lambda-functions">Async lambda functions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#performance">Performance</a><ul>
|
||
<li><a class="reference internal" href="#overall-impact">Overall Impact</a></li>
|
||
<li><a class="reference internal" href="#tokenizer-modifications">Tokenizer modifications</a></li>
|
||
<li><a class="reference internal" href="#async-await">async/await</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a><ul>
|
||
<li><a class="reference internal" href="#list-of-high-level-changes-and-new-protocols">List of high-level changes and new protocols</a></li>
|
||
<li><a class="reference internal" href="#working-example">Working example</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#acceptance">Acceptance</a></li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a></li>
|
||
<li><a class="reference internal" href="#references">References</a></li>
|
||
<li><a class="reference internal" href="#acknowledgments">Acknowledgments</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>The growth of Internet and general connectivity has triggered the
|
||
proportionate need for responsive and scalable code. This proposal
|
||
aims to answer that need by making writing explicitly asynchronous,
|
||
concurrent Python code easier and more Pythonic.</p>
|
||
<p>It is proposed to make <em>coroutines</em> a proper standalone concept in
|
||
Python, and introduce new supporting syntax. The ultimate goal
|
||
is to help establish a common, easily approachable, mental
|
||
model of asynchronous programming in Python and make it as close to
|
||
synchronous programming as possible.</p>
|
||
<p>This PEP assumes that the asynchronous tasks are scheduled and
|
||
coordinated by an Event Loop similar to that of stdlib module
|
||
<code class="docutils literal notranslate"><span class="pre">asyncio.events.AbstractEventLoop</span></code>. While the PEP is not tied to any
|
||
specific Event Loop implementation, it is relevant only to the kind of
|
||
coroutine that uses <code class="docutils literal notranslate"><span class="pre">yield</span></code> as a signal to the scheduler, indicating
|
||
that the coroutine will be waiting until an event (such as IO) is
|
||
completed.</p>
|
||
<p>We believe that the changes proposed here will help keep Python
|
||
relevant and competitive in a quickly growing area of asynchronous
|
||
programming, as many other languages have adopted, or are planning to
|
||
adopt, similar features: <a class="footnote-reference brackets" href="#id32" id="id1">[2]</a>, <a class="footnote-reference brackets" href="#id35" id="id2">[5]</a>, <a class="footnote-reference brackets" href="#id36" id="id3">[6]</a>, <a class="footnote-reference brackets" href="#id37" id="id4">[7]</a>, <a class="footnote-reference brackets" href="#id38" id="id5">[8]</a>, <a class="footnote-reference brackets" href="#id40" id="id6">[10]</a>.</p>
|
||
</section>
|
||
<section id="api-design-and-implementation-revisions">
|
||
<h2><a class="toc-backref" href="#api-design-and-implementation-revisions" role="doc-backlink">API Design and Implementation Revisions</a></h2>
|
||
<ol class="arabic">
|
||
<li>Feedback on the initial beta release of Python 3.5 resulted in a
|
||
redesign of the object model supporting this PEP to more clearly
|
||
separate native coroutines from generators - rather than being a
|
||
new kind of generator, native coroutines are now their own
|
||
completely distinct type (implemented in <a class="footnote-reference brackets" href="#id47" id="id7">[17]</a>).<p>This change was implemented based primarily due to problems
|
||
encountered attempting to integrate support for native coroutines
|
||
into the Tornado web server (reported in <a class="footnote-reference brackets" href="#id48" id="id8">[18]</a>).</p>
|
||
</li>
|
||
<li>In CPython 3.5.2, the <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> protocol was updated.<p>Before 3.5.2, <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> was expected to return an <em>awaitable</em>
|
||
resolving to an <em>asynchronous iterator</em>. Starting with 3.5.2,
|
||
<code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> should return asynchronous iterators directly.</p>
|
||
<p>If the old protocol is used in 3.5.2, Python will raise a
|
||
<code class="docutils literal notranslate"><span class="pre">PendingDeprecationWarning</span></code>.</p>
|
||
<p>In CPython 3.6, the old <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> protocol will still be
|
||
supported with a <code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code> being raised.</p>
|
||
<p>In CPython 3.7, the old <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> protocol will no longer be
|
||
supported: a <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code> will be raised if <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code>
|
||
returns anything but an asynchronous iterator.</p>
|
||
<p>See <a class="footnote-reference brackets" href="#id49" id="id9">[19]</a> and <a class="footnote-reference brackets" href="#id50" id="id10">[20]</a> for more details.</p>
|
||
</li>
|
||
</ol>
|
||
</section>
|
||
<section id="rationale-and-goals">
|
||
<h2><a class="toc-backref" href="#rationale-and-goals" role="doc-backlink">Rationale and Goals</a></h2>
|
||
<p>Current Python supports implementing coroutines via generators (PEP
|
||
342), further enhanced by the <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> syntax introduced in PEP
|
||
380. This approach has a number of shortcomings:</p>
|
||
<ul class="simple">
|
||
<li>It is easy to confuse coroutines with regular generators, since they
|
||
share the same syntax; this is especially true for new developers.</li>
|
||
<li>Whether or not a function is a coroutine is determined by a presence
|
||
of <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> statements in its <em>body</em>, which can
|
||
lead to unobvious errors when such statements appear in or disappear
|
||
from function body during refactoring.</li>
|
||
<li>Support for asynchronous calls is limited to expressions where
|
||
<code class="docutils literal notranslate"><span class="pre">yield</span></code> is allowed syntactically, limiting the usefulness of
|
||
syntactic features, such as <code class="docutils literal notranslate"><span class="pre">with</span></code> and <code class="docutils literal notranslate"><span class="pre">for</span></code> statements.</li>
|
||
</ul>
|
||
<p>This proposal makes coroutines a native Python language feature, and
|
||
clearly separates them from generators. This removes
|
||
generator/coroutine ambiguity, and makes it possible to reliably define
|
||
coroutines without reliance on a specific library. This also enables
|
||
linters and IDEs to improve static code analysis and refactoring.</p>
|
||
<p>Native coroutines and the associated new syntax features make it
|
||
possible to define context manager and iteration protocols in
|
||
asynchronous terms. As shown later in this proposal, the new <code class="docutils literal notranslate"><span class="pre">async</span>
|
||
<span class="pre">with</span></code> statement lets Python programs perform asynchronous calls when
|
||
entering and exiting a runtime context, and the new <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code>
|
||
statement makes it possible to perform asynchronous calls in iterators.</p>
|
||
</section>
|
||
<section id="specification">
|
||
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
||
<p>This proposal introduces new syntax and semantics to enhance coroutine
|
||
support in Python.</p>
|
||
<p>This specification presumes knowledge of the implementation of
|
||
coroutines in Python (<a class="pep reference internal" href="../pep-0342/" title="PEP 342 – Coroutines via Enhanced Generators">PEP 342</a> and <a class="pep reference internal" href="../pep-0380/" title="PEP 380 – Syntax for Delegating to a Subgenerator">PEP 380</a>). Motivation for the syntax
|
||
changes proposed here comes from the asyncio framework (<a class="pep reference internal" href="../pep-3156/" title="PEP 3156 – Asynchronous IO Support Rebooted: the “asyncio” Module">PEP 3156</a>) and
|
||
the “Cofunctions” proposal (<a class="pep reference internal" href="../pep-3152/" title="PEP 3152 – Cofunctions">PEP 3152</a>, now rejected in favor of this
|
||
specification).</p>
|
||
<p>From this point in this document we use the word <em>native coroutine</em> to
|
||
refer to functions declared using the new syntax. <em>generator-based
|
||
coroutine</em> is used where necessary to refer to coroutines that are
|
||
based on generator syntax. <em>coroutine</em> is used in contexts where both
|
||
definitions are applicable.</p>
|
||
<section id="new-coroutine-declaration-syntax">
|
||
<h3><a class="toc-backref" href="#new-coroutine-declaration-syntax" role="doc-backlink">New Coroutine Declaration Syntax</a></h3>
|
||
<p>The following new syntax is used to declare a <em>native coroutine</em>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">read_data</span><span class="p">(</span><span class="n">db</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Key properties of <em>coroutines</em>:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> functions are always coroutines, even if they do not
|
||
contain <code class="docutils literal notranslate"><span class="pre">await</span></code> expressions.</li>
|
||
<li>It is a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code> to have <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 in an <code class="docutils literal notranslate"><span class="pre">async</span></code> function.</li>
|
||
<li>Internally, two new code object flags were introduced:<ul>
|
||
<li><code class="docutils literal notranslate"><span class="pre">CO_COROUTINE</span></code> is used to mark <em>native coroutines</em>
|
||
(defined with new syntax).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">CO_ITERABLE_COROUTINE</span></code> is used to make <em>generator-based
|
||
coroutines</em> compatible with <em>native coroutines</em> (set by
|
||
<a class="reference internal" href="#types-coroutine">types.coroutine()</a> function).</li>
|
||
</ul>
|
||
</li>
|
||
<li>Regular generators, when called, return a <em>generator object</em>;
|
||
similarly, coroutines return a <em>coroutine</em> object.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> exceptions are not propagated out of coroutines,
|
||
and are replaced with a <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code>. For regular generators
|
||
such behavior requires a future import (see <a class="pep reference internal" href="../pep-0479/" title="PEP 479 – Change StopIteration handling inside generators">PEP 479</a>).</li>
|
||
<li>When a <em>native coroutine</em> is garbage collected, a <code class="docutils literal notranslate"><span class="pre">RuntimeWarning</span></code>
|
||
is raised if it was never awaited on (see also
|
||
<a class="reference internal" href="#debugging-features">Debugging Features</a>).</li>
|
||
<li>See also <a class="reference internal" href="#coroutine-objects">Coroutine objects</a> section.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="types-coroutine">
|
||
<h3><a class="toc-backref" href="#types-coroutine" role="doc-backlink">types.coroutine()</a></h3>
|
||
<p>A new function <code class="docutils literal notranslate"><span class="pre">coroutine(fn)</span></code> is added to the <code class="docutils literal notranslate"><span class="pre">types</span></code> module. It
|
||
allows interoperability between existing <em>generator-based coroutines</em>
|
||
in asyncio and <em>native coroutines</em> introduced by this PEP:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@types</span><span class="o">.</span><span class="n">coroutine</span>
|
||
<span class="k">def</span> <span class="nf">process_data</span><span class="p">(</span><span class="n">db</span><span class="p">):</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">read_data</span><span class="p">(</span><span class="n">db</span><span class="p">)</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The function applies <code class="docutils literal notranslate"><span class="pre">CO_ITERABLE_COROUTINE</span></code> flag to
|
||
generator-function’s code object, making it return a <em>coroutine</em> object.</p>
|
||
<p>If <code class="docutils literal notranslate"><span class="pre">fn</span></code> is not a <em>generator function</em>, it is wrapped. If it returns
|
||
a <em>generator</em>, it will be wrapped in an <em>awaitable</em> proxy object
|
||
(see below the definition of awaitable objects).</p>
|
||
<p>Note, that the <code class="docutils literal notranslate"><span class="pre">CO_COROUTINE</span></code> flag is not applied by
|
||
<code class="docutils literal notranslate"><span class="pre">types.coroutine()</span></code> to make it possible to separate <em>native
|
||
coroutines</em> defined with new syntax, from <em>generator-based coroutines</em>.</p>
|
||
</section>
|
||
<section id="await-expression">
|
||
<h3><a class="toc-backref" href="#await-expression" role="doc-backlink">Await Expression</a></h3>
|
||
<p>The following new <code class="docutils literal notranslate"><span class="pre">await</span></code> expression is used to obtain a result of
|
||
coroutine execution:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">read_data</span><span class="p">(</span><span class="n">db</span><span class="p">):</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s1">'SELECT ...'</span><span class="p">)</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">await</span></code>, similarly to <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code>, suspends execution of
|
||
<code class="docutils literal notranslate"><span class="pre">read_data</span></code> coroutine until <code class="docutils literal notranslate"><span class="pre">db.fetch</span></code> <em>awaitable</em> completes and
|
||
returns the result data.</p>
|
||
<p>It uses the <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> implementation with an extra step of
|
||
validating its argument. <code class="docutils literal notranslate"><span class="pre">await</span></code> only accepts an <em>awaitable</em>, which
|
||
can be one of:</p>
|
||
<ul>
|
||
<li>A <em>native coroutine</em> object returned from a <em>native coroutine
|
||
function</em>.</li>
|
||
<li>A <em>generator-based coroutine</em> object returned from a function
|
||
decorated with <code class="docutils literal notranslate"><span class="pre">types.coroutine()</span></code>.</li>
|
||
<li>An object with an <code class="docutils literal notranslate"><span class="pre">__await__</span></code> method returning an iterator.<p>Any <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> chain of calls ends with a <code class="docutils literal notranslate"><span class="pre">yield</span></code>. This is a
|
||
fundamental mechanism of how <em>Futures</em> are implemented. Since,
|
||
internally, coroutines are a special kind of generators, every
|
||
<code class="docutils literal notranslate"><span class="pre">await</span></code> is suspended by a <code class="docutils literal notranslate"><span class="pre">yield</span></code> somewhere down the chain of
|
||
<code class="docutils literal notranslate"><span class="pre">await</span></code> calls (please refer to <a class="pep reference internal" href="../pep-3156/" title="PEP 3156 – Asynchronous IO Support Rebooted: the “asyncio” Module">PEP 3156</a> for a detailed
|
||
explanation).</p>
|
||
<p>To enable this behavior for coroutines, a new magic method called
|
||
<code class="docutils literal notranslate"><span class="pre">__await__</span></code> is added. In asyncio, for instance, to enable <em>Future</em>
|
||
objects in <code class="docutils literal notranslate"><span class="pre">await</span></code> statements, the only change is to add
|
||
<code class="docutils literal notranslate"><span class="pre">__await__</span> <span class="pre">=</span> <span class="pre">__iter__</span></code> line to <code class="docutils literal notranslate"><span class="pre">asyncio.Future</span></code> class.</p>
|
||
<p>Objects with <code class="docutils literal notranslate"><span class="pre">__await__</span></code> method are called <em>Future-like</em> objects in
|
||
the rest of this PEP.</p>
|
||
<p>It is a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> if <code class="docutils literal notranslate"><span class="pre">__await__</span></code> returns anything but an
|
||
iterator.</p>
|
||
</li>
|
||
<li>Objects defined with CPython C API with a <code class="docutils literal notranslate"><span class="pre">tp_as_async.am_await</span></code>
|
||
function, returning an <em>iterator</em> (similar to <code class="docutils literal notranslate"><span class="pre">__await__</span></code> method).</li>
|
||
</ul>
|
||
<p>It is a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code> to use <code class="docutils literal notranslate"><span class="pre">await</span></code> outside of an <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code>
|
||
function (like it is a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code> to use <code class="docutils literal notranslate"><span class="pre">yield</span></code> outside of
|
||
<code class="docutils literal notranslate"><span class="pre">def</span></code> function).</p>
|
||
<p>It is a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> to pass anything other than an <em>awaitable</em> object
|
||
to an <code class="docutils literal notranslate"><span class="pre">await</span></code> expression.</p>
|
||
<section id="updated-operator-precedence-table">
|
||
<h4><a class="toc-backref" href="#updated-operator-precedence-table" role="doc-backlink">Updated operator precedence table</a></h4>
|
||
<p><code class="docutils literal notranslate"><span class="pre">await</span></code> keyword is defined as follows:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">power</span> <span class="p">:</span><span class="o">:=</span> <span class="k">await</span> <span class="p">[</span><span class="s2">"**"</span> <span class="n">u_expr</span><span class="p">]</span>
|
||
<span class="k">await</span> <span class="p">:</span><span class="o">:=</span> <span class="p">[</span><span class="s2">"await"</span><span class="p">]</span> <span class="n">primary</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>where “primary” represents the most tightly bound operations of the
|
||
language. Its syntax is:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">primary</span> <span class="p">:</span><span class="o">:=</span> <span class="n">atom</span> <span class="o">|</span> <span class="n">attributeref</span> <span class="o">|</span> <span class="n">subscription</span> <span class="o">|</span> <span class="n">slicing</span> <span class="o">|</span> <span class="n">call</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>See Python Documentation <a class="footnote-reference brackets" href="#id42" id="id11">[12]</a> and <a class="reference internal" href="#grammar-updates">Grammar Updates</a> section of this
|
||
proposal for details.</p>
|
||
<p>The key <code class="docutils literal notranslate"><span class="pre">await</span></code> difference from <code class="docutils literal notranslate"><span class="pre">yield</span></code> and <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code>
|
||
operators is that <em>await expressions</em> do not require parentheses around
|
||
them most of the times.</p>
|
||
<p>Also, <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> allows any expression as its argument, including
|
||
expressions like <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span> <span class="pre">a()</span> <span class="pre">+</span> <span class="pre">b()</span></code>, that would be parsed as
|
||
<code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span> <span class="pre">(a()</span> <span class="pre">+</span> <span class="pre">b())</span></code>, which is almost always a bug. In general,
|
||
the result of any arithmetic operation is not an <em>awaitable</em> object.
|
||
To avoid this kind of mistakes, it was decided to make <code class="docutils literal notranslate"><span class="pre">await</span></code>
|
||
precedence lower than <code class="docutils literal notranslate"><span class="pre">[]</span></code>, <code class="docutils literal notranslate"><span class="pre">()</span></code>, and <code class="docutils literal notranslate"><span class="pre">.</span></code>, but higher than <code class="docutils literal notranslate"><span class="pre">**</span></code>
|
||
operators.</p>
|
||
<table class="docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head">Operator</th>
|
||
<th class="head">Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">yield</span></code> <code class="docutils literal notranslate"><span class="pre">x</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> <code class="docutils literal notranslate"><span class="pre">x</span></code></td>
|
||
<td>Yield expression</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">lambda</span></code></td>
|
||
<td>Lambda expression</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">if</span></code> – <code class="docutils literal notranslate"><span class="pre">else</span></code></td>
|
||
<td>Conditional expression</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">or</span></code></td>
|
||
<td>Boolean OR</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">and</span></code></td>
|
||
<td>Boolean AND</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">not</span></code> <code class="docutils literal notranslate"><span class="pre">x</span></code></td>
|
||
<td>Boolean NOT</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">in</span></code>, <code class="docutils literal notranslate"><span class="pre">not</span> <span class="pre">in</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">is</span></code>, <code class="docutils literal notranslate"><span class="pre">is</span> <span class="pre">not</span></code>, <code class="docutils literal notranslate"><span class="pre"><</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre"><=</span></code>, <code class="docutils literal notranslate"><span class="pre">></span></code>, <code class="docutils literal notranslate"><span class="pre">>=</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">!=</span></code>, <code class="docutils literal notranslate"><span class="pre">==</span></code></td>
|
||
<td>Comparisons, including membership
|
||
tests and identity tests</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">|</span></code></td>
|
||
<td>Bitwise OR</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">^</span></code></td>
|
||
<td>Bitwise XOR</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">&</span></code></td>
|
||
<td>Bitwise AND</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre"><<</span></code>, <code class="docutils literal notranslate"><span class="pre">>></span></code></td>
|
||
<td>Shifts</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">+</span></code>, <code class="docutils literal notranslate"><span class="pre">-</span></code></td>
|
||
<td>Addition and subtraction</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">*</span></code>, <code class="docutils literal notranslate"><span class="pre">@</span></code>, <code class="docutils literal notranslate"><span class="pre">/</span></code>, <code class="docutils literal notranslate"><span class="pre">//</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">%</span></code></td>
|
||
<td>Multiplication, matrix
|
||
multiplication, division,
|
||
remainder</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">+x</span></code>, <code class="docutils literal notranslate"><span class="pre">-x</span></code>, <code class="docutils literal notranslate"><span class="pre">~x</span></code></td>
|
||
<td>Positive, negative, bitwise NOT</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">**</span></code></td>
|
||
<td>Exponentiation</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">await</span></code> <code class="docutils literal notranslate"><span class="pre">x</span></code></td>
|
||
<td>Await expression</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">x[index]</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">x[index:index]</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">x(arguments...)</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">x.attribute</span></code></td>
|
||
<td>Subscription, slicing,
|
||
call, attribute reference</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">(expressions...)</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">[expressions...]</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">{key:</span> <span class="pre">value...}</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">{expressions...}</span></code></td>
|
||
<td>Binding or tuple display,
|
||
list display,
|
||
dictionary display,
|
||
set display</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
<section id="examples-of-await-expressions">
|
||
<h4><a class="toc-backref" href="#examples-of-await-expressions" role="doc-backlink">Examples of “await” expressions</a></h4>
|
||
<p>Valid syntax examples:</p>
|
||
<table class="docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head">Expression</th>
|
||
<th class="head">Will be parsed as</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">await</span> <span class="pre">fut:</span> <span class="pre">pass</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">(await</span> <span class="pre">fut):</span> <span class="pre">pass</span></code></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">await</span> <span class="pre">fut</span> <span class="pre">+</span> <span class="pre">1:</span> <span class="pre">pass</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">(await</span> <span class="pre">fut)</span> <span class="pre">+</span> <span class="pre">1:</span> <span class="pre">pass</span></code></td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">pair</span> <span class="pre">=</span> <span class="pre">await</span> <span class="pre">fut,</span> <span class="pre">'spam'</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">pair</span> <span class="pre">=</span> <span class="pre">(await</span> <span class="pre">fut),</span> <span class="pre">'spam'</span></code></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">with</span> <span class="pre">await</span> <span class="pre">fut,</span> <span class="pre">open():</span> <span class="pre">pass</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">with</span> <span class="pre">(await</span> <span class="pre">fut),</span> <span class="pre">open():</span> <span class="pre">pass</span></code></td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">foo()['spam'].baz()()</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">(</span> <span class="pre">foo()['spam'].baz()()</span> <span class="pre">)</span></code></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">await</span> <span class="pre">coro()</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">(</span> <span class="pre">await</span> <span class="pre">coro()</span> <span class="pre">)</span></code></td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">res</span> <span class="pre">=</span> <span class="pre">await</span> <span class="pre">coro()</span> <span class="pre">**</span> <span class="pre">2</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">res</span> <span class="pre">=</span> <span class="pre">(await</span> <span class="pre">coro())</span> <span class="pre">**</span> <span class="pre">2</span></code></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">func(a1=await</span> <span class="pre">coro(),</span> <span class="pre">a2=0)</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">func(a1=(await</span> <span class="pre">coro()),</span> <span class="pre">a2=0)</span></code></td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">foo()</span> <span class="pre">+</span> <span class="pre">await</span> <span class="pre">bar()</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">(await</span> <span class="pre">foo())</span> <span class="pre">+</span> <span class="pre">(await</span> <span class="pre">bar())</span></code></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">-await</span> <span class="pre">foo()</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">-(await</span> <span class="pre">foo())</span></code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Invalid syntax examples:</p>
|
||
<table class="docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head">Expression</th>
|
||
<th class="head">Should be written as</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">await</span> <span class="pre">coro()</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">(await</span> <span class="pre">coro())</span></code></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">-coro()</span></code></td>
|
||
<td><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">(-coro())</span></code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
</section>
|
||
<section id="asynchronous-context-managers-and-async-with">
|
||
<h3><a class="toc-backref" href="#asynchronous-context-managers-and-async-with" role="doc-backlink">Asynchronous Context Managers and “async with”</a></h3>
|
||
<p>An <em>asynchronous context manager</em> is a context manager that is able to
|
||
suspend execution in its <em>enter</em> and <em>exit</em> methods.</p>
|
||
<p>To make this possible, a new protocol for asynchronous context managers
|
||
is proposed. Two new magic methods are added: <code class="docutils literal notranslate"><span class="pre">__aenter__</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">__aexit__</span></code>. Both must return an <em>awaitable</em>.</p>
|
||
<p>An example of an asynchronous context manager:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">AsyncContextManager</span><span class="p">:</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="fm">__aenter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">log</span><span class="p">(</span><span class="s1">'entering context'</span><span class="p">)</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="fm">__aexit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exc_type</span><span class="p">,</span> <span class="n">exc</span><span class="p">,</span> <span class="n">tb</span><span class="p">):</span>
|
||
<span class="k">await</span> <span class="n">log</span><span class="p">(</span><span class="s1">'exiting context'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="new-syntax">
|
||
<h4><a class="toc-backref" href="#new-syntax" role="doc-backlink">New Syntax</a></h4>
|
||
<p>A new statement for asynchronous context managers is proposed:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">with</span> <span class="n">EXPR</span> <span class="k">as</span> <span class="n">VAR</span><span class="p">:</span>
|
||
<span class="n">BLOCK</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>which is semantically equivalent to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mgr</span> <span class="o">=</span> <span class="p">(</span><span class="n">EXPR</span><span class="p">)</span>
|
||
<span class="n">aexit</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">mgr</span><span class="p">)</span><span class="o">.</span><span class="fm">__aexit__</span>
|
||
<span class="n">aenter</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">mgr</span><span class="p">)</span><span class="o">.</span><span class="fm">__aenter__</span>
|
||
|
||
<span class="n">VAR</span> <span class="o">=</span> <span class="k">await</span> <span class="n">aenter</span><span class="p">(</span><span class="n">mgr</span><span class="p">)</span>
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">BLOCK</span>
|
||
<span class="k">except</span><span class="p">:</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="k">await</span> <span class="n">aexit</span><span class="p">(</span><span class="n">mgr</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="k">raise</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="k">await</span> <span class="n">aexit</span><span class="p">(</span><span class="n">mgr</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>As with regular <code class="docutils literal notranslate"><span class="pre">with</span></code> statements, it is possible to specify multiple
|
||
context managers in a single <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code> statement.</p>
|
||
<p>It is an error to pass a regular context manager without <code class="docutils literal notranslate"><span class="pre">__aenter__</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">__aexit__</span></code> methods to <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code>. It is a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code>
|
||
to use <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code> outside of an <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> function.</p>
|
||
</section>
|
||
<section id="example">
|
||
<h4><a class="toc-backref" href="#example" role="doc-backlink">Example</a></h4>
|
||
<p>With <em>asynchronous context managers</em> it is easy to implement proper
|
||
database transaction managers for coroutines:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">commit</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
|
||
<span class="k">async</span> <span class="k">with</span> <span class="n">session</span><span class="o">.</span><span class="n">transaction</span><span class="p">():</span>
|
||
<span class="o">...</span>
|
||
<span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Code that needs locking also looks lighter:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">with</span> <span class="n">lock</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>instead of:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">with</span> <span class="p">(</span><span class="k">yield from</span> <span class="n">lock</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="asynchronous-iterators-and-async-for">
|
||
<h3><a class="toc-backref" href="#asynchronous-iterators-and-async-for" role="doc-backlink">Asynchronous Iterators and “async for”</a></h3>
|
||
<p>An <em>asynchronous iterable</em> is able to call asynchronous code in its
|
||
<em>iter</em> implementation, and <em>asynchronous iterator</em> can call
|
||
asynchronous code in its <em>next</em> method. To support asynchronous
|
||
iteration:</p>
|
||
<ol class="arabic simple">
|
||
<li>An object must implement an <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> method (or, if defined
|
||
with CPython C API, <code class="docutils literal notranslate"><span class="pre">tp_as_async.am_aiter</span></code> slot) returning an
|
||
<em>asynchronous iterator object</em>.</li>
|
||
<li>An <em>asynchronous iterator object</em> must implement an <code class="docutils literal notranslate"><span class="pre">__anext__</span></code>
|
||
method (or, if defined with CPython C API, <code class="docutils literal notranslate"><span class="pre">tp_as_async.am_anext</span></code>
|
||
slot) returning an <em>awaitable</em>.</li>
|
||
<li>To stop iteration <code class="docutils literal notranslate"><span class="pre">__anext__</span></code> must raise a <code class="docutils literal notranslate"><span class="pre">StopAsyncIteration</span></code>
|
||
exception.</li>
|
||
</ol>
|
||
<p>An example of asynchronous iterable:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">AsyncIterable</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="fm">__aiter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="fm">__anext__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">fetch_data</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="n">data</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">data</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="k">raise</span> <span class="ne">StopAsyncIteration</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">fetch_data</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="id12">
|
||
<h4><a class="toc-backref" href="#id12" role="doc-backlink">New Syntax</a></h4>
|
||
<p>A new statement for iterating through asynchronous iterators is
|
||
proposed:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">for</span> <span class="n">TARGET</span> <span class="ow">in</span> <span class="n">ITER</span><span class="p">:</span>
|
||
<span class="n">BLOCK</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">BLOCK2</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>which is semantically equivalent to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">iter</span> <span class="o">=</span> <span class="p">(</span><span class="n">ITER</span><span class="p">)</span>
|
||
<span class="nb">iter</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="nb">iter</span><span class="p">)</span><span class="o">.</span><span class="fm">__aiter__</span><span class="p">(</span><span class="nb">iter</span><span class="p">)</span>
|
||
<span class="n">running</span> <span class="o">=</span> <span class="kc">True</span>
|
||
<span class="k">while</span> <span class="n">running</span><span class="p">:</span>
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">TARGET</span> <span class="o">=</span> <span class="k">await</span> <span class="nb">type</span><span class="p">(</span><span class="nb">iter</span><span class="p">)</span><span class="o">.</span><span class="fm">__anext__</span><span class="p">(</span><span class="nb">iter</span><span class="p">)</span>
|
||
<span class="k">except</span> <span class="ne">StopAsyncIteration</span><span class="p">:</span>
|
||
<span class="n">running</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">BLOCK</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">BLOCK2</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>It is a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> to pass a regular iterable without <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code>
|
||
method to <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code>. It is a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code> to use <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code>
|
||
outside of an <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> function.</p>
|
||
<p>As for with regular <code class="docutils literal notranslate"><span class="pre">for</span></code> statement, <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code> has an optional
|
||
<code class="docutils literal notranslate"><span class="pre">else</span></code> clause.</p>
|
||
</section>
|
||
<section id="example-1">
|
||
<h4><a class="toc-backref" href="#example-1" role="doc-backlink">Example 1</a></h4>
|
||
<p>With asynchronous iteration protocol it is possible to asynchronously
|
||
buffer data during iteration:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">for</span> <span class="n">data</span> <span class="ow">in</span> <span class="n">cursor</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Where <code class="docutils literal notranslate"><span class="pre">cursor</span></code> is an asynchronous iterator that prefetches <code class="docutils literal notranslate"><span class="pre">N</span></code> rows
|
||
of data from a database after every <code class="docutils literal notranslate"><span class="pre">N</span></code> iterations.</p>
|
||
<p>The following code illustrates new asynchronous iteration protocol:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Cursor</span><span class="p">:</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">buffer</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">async</span> <span class="k">def</span> <span class="nf">_prefetch</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
|
||
<span class="k">def</span> <span class="fm">__aiter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="fm">__anext__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffer</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">buffer</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_prefetch</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffer</span><span class="p">:</span>
|
||
<span class="k">raise</span> <span class="ne">StopAsyncIteration</span>
|
||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">buffer</span><span class="o">.</span><span class="n">popleft</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>then the <code class="docutils literal notranslate"><span class="pre">Cursor</span></code> class can be used as follows:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">Cursor</span><span class="p">():</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>which would be equivalent to the following code:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">i</span> <span class="o">=</span> <span class="n">Cursor</span><span class="p">()</span><span class="o">.</span><span class="fm">__aiter__</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">row</span> <span class="o">=</span> <span class="k">await</span> <span class="n">i</span><span class="o">.</span><span class="fm">__anext__</span><span class="p">()</span>
|
||
<span class="k">except</span> <span class="ne">StopAsyncIteration</span><span class="p">:</span>
|
||
<span class="k">break</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="example-2">
|
||
<h4><a class="toc-backref" href="#example-2" role="doc-backlink">Example 2</a></h4>
|
||
<p>The following is a utility class that transforms a regular iterable to
|
||
an asynchronous one. While this is not a very useful thing to do, the
|
||
code illustrates the relationship between regular and asynchronous
|
||
iterators.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">AsyncIteratorWrapper</span><span class="p">:</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="n">obj</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_it</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="fm">__aiter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="fm">__anext__</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="n">value</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_it</span><span class="p">)</span>
|
||
<span class="k">except</span> <span class="ne">StopIteration</span><span class="p">:</span>
|
||
<span class="k">raise</span> <span class="ne">StopAsyncIteration</span>
|
||
<span class="k">return</span> <span class="n">value</span>
|
||
|
||
<span class="k">async</span> <span class="k">for</span> <span class="n">letter</span> <span class="ow">in</span> <span class="n">AsyncIteratorWrapper</span><span class="p">(</span><span class="s2">"abc"</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="why-stopasynciteration">
|
||
<h4><a class="toc-backref" href="#why-stopasynciteration" role="doc-backlink">Why StopAsyncIteration?</a></h4>
|
||
<p>Coroutines are still based on generators internally. So, before PEP
|
||
479, there was no fundamental difference between</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">g1</span><span class="p">():</span>
|
||
<span class="k">yield from</span> <span class="n">fut</span>
|
||
<span class="k">return</span> <span class="s1">'spam'</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>and</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">g2</span><span class="p">():</span>
|
||
<span class="k">yield from</span> <span class="n">fut</span>
|
||
<span class="k">raise</span> <span class="ne">StopIteration</span><span class="p">(</span><span class="s1">'spam'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>And since <a class="pep reference internal" href="../pep-0479/" title="PEP 479 – Change StopIteration handling inside generators">PEP 479</a> is accepted and enabled by default for coroutines,
|
||
the following example will have its <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> wrapped into a
|
||
<code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code></p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span> <span class="nf">a1</span><span class="p">():</span>
|
||
<span class="k">await</span> <span class="n">fut</span>
|
||
<span class="k">raise</span> <span class="ne">StopIteration</span><span class="p">(</span><span class="s1">'spam'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The only way to tell the outside code that the iteration has ended is
|
||
to raise something other than <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code>. Therefore, a new
|
||
built-in exception class <code class="docutils literal notranslate"><span class="pre">StopAsyncIteration</span></code> was added.</p>
|
||
<p>Moreover, with semantics from <a class="pep reference internal" href="../pep-0479/" title="PEP 479 – Change StopIteration handling inside generators">PEP 479</a>, all <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> exceptions
|
||
raised in coroutines are wrapped in <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code>.</p>
|
||
</section>
|
||
</section>
|
||
<section id="coroutine-objects">
|
||
<h3><a class="toc-backref" href="#coroutine-objects" role="doc-backlink">Coroutine objects</a></h3>
|
||
<section id="differences-from-generators">
|
||
<h4><a class="toc-backref" href="#differences-from-generators" role="doc-backlink">Differences from generators</a></h4>
|
||
<p>This section applies only to <em>native coroutines</em> with <code class="docutils literal notranslate"><span class="pre">CO_COROUTINE</span></code>
|
||
flag, i.e. defined with the new <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> syntax.</p>
|
||
<p><strong>The behavior of existing *generator-based coroutines* in asyncio
|
||
remains unchanged.</strong></p>
|
||
<p>Great effort has been made to make sure that coroutines and
|
||
generators are treated as distinct concepts:</p>
|
||
<ol class="arabic">
|
||
<li><em>Native coroutine</em> objects do not implement <code class="docutils literal notranslate"><span class="pre">__iter__</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">__next__</span></code> methods. Therefore, they cannot be iterated over or
|
||
passed to <code class="docutils literal notranslate"><span class="pre">iter()</span></code>, <code class="docutils literal notranslate"><span class="pre">list()</span></code>, <code class="docutils literal notranslate"><span class="pre">tuple()</span></code> and other built-ins.
|
||
They also cannot be used in a <code class="docutils literal notranslate"><span class="pre">for..in</span></code> loop.<p>An attempt to use <code class="docutils literal notranslate"><span class="pre">__iter__</span></code> or <code class="docutils literal notranslate"><span class="pre">__next__</span></code> on a <em>native
|
||
coroutine</em> object will result in a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>.</p>
|
||
</li>
|
||
<li><em>Plain generators</em> cannot <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> <em>native coroutines</em>:
|
||
doing so will result in a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>.</li>
|
||
<li><em>generator-based coroutines</em> (for asyncio code must be decorated
|
||
with <code class="docutils literal notranslate"><span class="pre">@asyncio.coroutine</span></code> <a class="footnote-reference brackets" href="#id31" id="id13">[1]</a>) can <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> <em>native coroutine
|
||
objects</em>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">inspect.isgenerator()</span></code> and <code class="docutils literal notranslate"><span class="pre">inspect.isgeneratorfunction()</span></code>
|
||
return <code class="docutils literal notranslate"><span class="pre">False</span></code> for <em>native coroutine</em> objects and <em>native
|
||
coroutine functions</em>.</li>
|
||
</ol>
|
||
</section>
|
||
<section id="coroutine-object-methods">
|
||
<h4><a class="toc-backref" href="#coroutine-object-methods" role="doc-backlink">Coroutine object methods</a></h4>
|
||
<p>Coroutines are based on generators internally, thus they share the
|
||
implementation. Similarly to generator objects, <em>coroutines</em> have
|
||
<code class="docutils literal notranslate"><span class="pre">throw()</span></code>, <code class="docutils literal notranslate"><span class="pre">send()</span></code> and <code class="docutils literal notranslate"><span class="pre">close()</span></code> methods. <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">GeneratorExit</span></code> play the same role for coroutines (although
|
||
<a class="pep reference internal" href="../pep-0479/" title="PEP 479 – Change StopIteration handling inside generators">PEP 479</a> is enabled by default for coroutines). See <a class="pep reference internal" href="../pep-0342/" title="PEP 342 – Coroutines via Enhanced Generators">PEP 342</a>, <a class="pep reference internal" href="../pep-0380/" title="PEP 380 – Syntax for Delegating to a Subgenerator">PEP 380</a>,
|
||
and Python Documentation <a class="footnote-reference brackets" href="#id41" id="id14">[11]</a> for details.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">throw()</span></code>, <code class="docutils literal notranslate"><span class="pre">send()</span></code> methods for <em>coroutines</em> are used to push
|
||
values and raise errors into <em>Future-like</em> objects.</p>
|
||
</section>
|
||
</section>
|
||
<section id="debugging-features">
|
||
<h3><a class="toc-backref" href="#debugging-features" role="doc-backlink">Debugging Features</a></h3>
|
||
<p>A common beginner mistake is forgetting to use <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> on
|
||
coroutines:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@asyncio</span><span class="o">.</span><span class="n">coroutine</span>
|
||
<span class="k">def</span> <span class="nf">useful</span><span class="p">():</span>
|
||
<span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># this will do nothing without 'yield from'</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>For debugging this kind of mistakes there is a special debug mode in
|
||
asyncio, in which <code class="docutils literal notranslate"><span class="pre">@coroutine</span></code> decorator wraps all functions with a
|
||
special object with a destructor logging a warning. Whenever a wrapped
|
||
generator gets garbage collected, a detailed logging message is
|
||
generated with information about where exactly the decorator function
|
||
was defined, stack trace of where it was collected, etc. Wrapper
|
||
object also provides a convenient <code class="docutils literal notranslate"><span class="pre">__repr__</span></code> function with detailed
|
||
information about the generator.</p>
|
||
<p>The only problem is how to enable these debug capabilities. Since
|
||
debug facilities should be a no-op in production mode, <code class="docutils literal notranslate"><span class="pre">@coroutine</span></code>
|
||
decorator makes the decision of whether to wrap or not to wrap based on
|
||
an OS environment variable <code class="docutils literal notranslate"><span class="pre">PYTHONASYNCIODEBUG</span></code>. This way it is
|
||
possible to run asyncio programs with asyncio’s own functions
|
||
instrumented. <code class="docutils literal notranslate"><span class="pre">EventLoop.set_debug</span></code>, a different debug facility, has
|
||
no impact on <code class="docutils literal notranslate"><span class="pre">@coroutine</span></code> decorator’s behavior.</p>
|
||
<p>With this proposal, coroutines is a native, distinct from generators,
|
||
concept. <em>In addition</em> to a <code class="docutils literal notranslate"><span class="pre">RuntimeWarning</span></code> being raised on
|
||
coroutines that were never awaited, it is proposed to add two new
|
||
functions to the <code class="docutils literal notranslate"><span class="pre">sys</span></code> module: <code class="docutils literal notranslate"><span class="pre">set_coroutine_wrapper</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">get_coroutine_wrapper</span></code>. This is to enable advanced debugging
|
||
facilities in asyncio and other frameworks (such as displaying where
|
||
exactly coroutine was created, and a more detailed stack trace of where
|
||
it was garbage collected).</p>
|
||
</section>
|
||
<section id="new-standard-library-functions">
|
||
<h3><a class="toc-backref" href="#new-standard-library-functions" role="doc-backlink">New Standard Library Functions</a></h3>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">types.coroutine(gen)</span></code>. See <a class="reference internal" href="#types-coroutine">types.coroutine()</a> section for
|
||
details.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">inspect.iscoroutine(obj)</span></code> returns <code class="docutils literal notranslate"><span class="pre">True</span></code> if <code class="docutils literal notranslate"><span class="pre">obj</span></code> is a
|
||
<em>native coroutine</em> object.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">inspect.iscoroutinefunction(obj)</span></code> returns <code class="docutils literal notranslate"><span class="pre">True</span></code> if <code class="docutils literal notranslate"><span class="pre">obj</span></code> is a
|
||
<em>native coroutine function</em>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">inspect.isawaitable(obj)</span></code> returns <code class="docutils literal notranslate"><span class="pre">True</span></code> if <code class="docutils literal notranslate"><span class="pre">obj</span></code> is an
|
||
<em>awaitable</em>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">inspect.getcoroutinestate(coro)</span></code> returns the current state of
|
||
a <em>native coroutine object</em> (mirrors
|
||
<code class="docutils literal notranslate"><span class="pre">inspect.getfgeneratorstate(gen)</span></code>).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">inspect.getcoroutinelocals(coro)</span></code> returns the mapping of a
|
||
<em>native coroutine object’s</em> local variables to their values
|
||
(mirrors <code class="docutils literal notranslate"><span class="pre">inspect.getgeneratorlocals(gen)</span></code>).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">sys.set_coroutine_wrapper(wrapper)</span></code> allows to intercept creation of
|
||
<em>native coroutine</em> objects. <code class="docutils literal notranslate"><span class="pre">wrapper</span></code> must be either a callable that
|
||
accepts one argument (a <em>coroutine</em> object), or <code class="docutils literal notranslate"><span class="pre">None</span></code>. <code class="docutils literal notranslate"><span class="pre">None</span></code>
|
||
resets the wrapper. If called twice, the new wrapper replaces the
|
||
previous one. The function is thread-specific. See <a class="reference internal" href="#debugging-features">Debugging
|
||
Features</a> for more details.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">sys.get_coroutine_wrapper()</span></code> returns the current wrapper object.
|
||
Returns <code class="docutils literal notranslate"><span class="pre">None</span></code> if no wrapper was set. The function is
|
||
thread-specific. See <a class="reference internal" href="#debugging-features">Debugging Features</a> for more details.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="new-abstract-base-classes">
|
||
<h3><a class="toc-backref" href="#new-abstract-base-classes" role="doc-backlink">New Abstract Base Classes</a></h3>
|
||
<p>In order to allow better integration with existing frameworks (such as
|
||
Tornado, see <a class="footnote-reference brackets" href="#id43" id="id15">[13]</a>) and compilers (such as Cython, see <a class="footnote-reference brackets" href="#id46" id="id16">[16]</a>), two new
|
||
Abstract Base Classes (ABC) are added:</p>
|
||
<ul>
|
||
<li><code class="docutils literal notranslate"><span class="pre">collections.abc.Awaitable</span></code> ABC for <em>Future-like</em> classes, that
|
||
implement <code class="docutils literal notranslate"><span class="pre">__await__</span></code> method.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">collections.abc.Coroutine</span></code> ABC for <em>coroutine</em> objects, that
|
||
implement <code class="docutils literal notranslate"><span class="pre">send(value)</span></code>, <code class="docutils literal notranslate"><span class="pre">throw(type,</span> <span class="pre">exc,</span> <span class="pre">tb)</span></code>, <code class="docutils literal notranslate"><span class="pre">close()</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">__await__()</span></code> methods.<p>Note that generator-based coroutines with <code class="docutils literal notranslate"><span class="pre">CO_ITERABLE_COROUTINE</span></code>
|
||
flag do not implement <code class="docutils literal notranslate"><span class="pre">__await__</span></code> method, and therefore are not
|
||
instances of <code class="docutils literal notranslate"><span class="pre">collections.abc.Coroutine</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">collections.abc.Awaitable</span></code> ABCs:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@types</span><span class="o">.</span><span class="n">coroutine</span>
|
||
<span class="k">def</span> <span class="nf">gencoro</span><span class="p">():</span>
|
||
<span class="k">yield</span>
|
||
|
||
<span class="k">assert</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">gencoro</span><span class="p">(),</span> <span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Coroutine</span><span class="p">)</span>
|
||
|
||
<span class="c1"># however:</span>
|
||
<span class="k">assert</span> <span class="n">inspect</span><span class="o">.</span><span class="n">isawaitable</span><span class="p">(</span><span class="n">gencoro</span><span class="p">())</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<p>To allow easy testing if objects support asynchronous iteration, two
|
||
more ABCs are added:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">collections.abc.AsyncIterable</span></code> – tests for <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> method.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">collections.abc.AsyncIterator</span></code> – tests for <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">__anext__</span></code> methods.</li>
|
||
</ul>
|
||
</section>
|
||
</section>
|
||
<section id="glossary">
|
||
<h2><a class="toc-backref" href="#glossary" role="doc-backlink">Glossary</a></h2>
|
||
<dl class="simple">
|
||
<dt>Native coroutine function</dt><dd>A coroutine function is declared with <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code>. It uses
|
||
<code class="docutils literal notranslate"><span class="pre">await</span></code> and <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">value</span></code>; see <a class="reference internal" href="#new-coroutine-declaration-syntax">New Coroutine Declaration
|
||
Syntax</a> for details.</dd>
|
||
<dt>Native coroutine</dt><dd>Returned from a native coroutine function. See <a class="reference internal" href="#await-expression">Await Expression</a>
|
||
for details.</dd>
|
||
<dt>Generator-based coroutine function</dt><dd>Coroutines based on generator syntax. Most common example are
|
||
functions decorated with <code class="docutils literal notranslate"><span class="pre">@asyncio.coroutine</span></code>.</dd>
|
||
<dt>Generator-based coroutine</dt><dd>Returned from a generator-based coroutine function.</dd>
|
||
<dt>Coroutine</dt><dd>Either <em>native coroutine</em> or <em>generator-based coroutine</em>.</dd>
|
||
<dt>Coroutine object</dt><dd>Either <em>native coroutine</em> object or <em>generator-based coroutine</em>
|
||
object.</dd>
|
||
<dt>Future-like object</dt><dd>An object with an <code class="docutils literal notranslate"><span class="pre">__await__</span></code> method, or a C object with
|
||
<code class="docutils literal notranslate"><span class="pre">tp_as_async->am_await</span></code> function, returning an <em>iterator</em>. Can be
|
||
consumed by an <code class="docutils literal notranslate"><span class="pre">await</span></code> expression in a coroutine. A coroutine
|
||
waiting for a Future-like object is suspended until the Future-like
|
||
object’s <code class="docutils literal notranslate"><span class="pre">__await__</span></code> completes, and returns the result. See
|
||
<a class="reference internal" href="#await-expression">Await Expression</a> for details.</dd>
|
||
<dt>Awaitable</dt><dd>A <em>Future-like</em> object or a <em>coroutine</em> object. See <a class="reference internal" href="#await-expression">Await
|
||
Expression</a> for details.</dd>
|
||
<dt>Asynchronous context manager</dt><dd>An asynchronous context manager has <code class="docutils literal notranslate"><span class="pre">__aenter__</span></code> and <code class="docutils literal notranslate"><span class="pre">__aexit__</span></code>
|
||
methods and can be used with <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code>. See <a class="reference internal" href="#asynchronous-context-managers-and-async-with">Asynchronous
|
||
Context Managers and “async with”</a> for details.</dd>
|
||
<dt>Asynchronous iterable</dt><dd>An object with an <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> method, which must return an
|
||
<em>asynchronous iterator</em> object. Can be used with <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code>.
|
||
See <a class="reference internal" href="#asynchronous-iterators-and-async-for">Asynchronous Iterators and “async for”</a> for details.</dd>
|
||
<dt>Asynchronous iterator</dt><dd>An asynchronous iterator has an <code class="docutils literal notranslate"><span class="pre">__anext__</span></code> method. See
|
||
<a class="reference internal" href="#asynchronous-iterators-and-async-for">Asynchronous Iterators and “async for”</a> for details.</dd>
|
||
</dl>
|
||
</section>
|
||
<section id="transition-plan">
|
||
<h2><a class="toc-backref" href="#transition-plan" role="doc-backlink">Transition Plan</a></h2>
|
||
<p>To avoid backwards compatibility issues with <code class="docutils literal notranslate"><span class="pre">async</span></code> and <code class="docutils literal notranslate"><span class="pre">await</span></code>
|
||
keywords, it was decided to modify <code class="docutils literal notranslate"><span class="pre">tokenizer.c</span></code> in such a way, that
|
||
it:</p>
|
||
<ul class="simple">
|
||
<li>recognizes <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> <code class="docutils literal notranslate"><span class="pre">NAME</span></code> tokens combination;</li>
|
||
<li>while tokenizing <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> block, it replaces <code class="docutils literal notranslate"><span class="pre">'async'</span></code>
|
||
<code class="docutils literal notranslate"><span class="pre">NAME</span></code> token with <code class="docutils literal notranslate"><span class="pre">ASYNC</span></code>, and <code class="docutils literal notranslate"><span class="pre">'await'</span></code> <code class="docutils literal notranslate"><span class="pre">NAME</span></code> token with
|
||
<code class="docutils literal notranslate"><span class="pre">AWAIT</span></code>;</li>
|
||
<li>while tokenizing <code class="docutils literal notranslate"><span class="pre">def</span></code> block, it yields <code class="docutils literal notranslate"><span class="pre">'async'</span></code> and <code class="docutils literal notranslate"><span class="pre">'await'</span></code>
|
||
<code class="docutils literal notranslate"><span class="pre">NAME</span></code> tokens as is.</li>
|
||
</ul>
|
||
<p>This approach allows for seamless combination of new syntax features
|
||
(all of them available only in <code class="docutils literal notranslate"><span class="pre">async</span></code> functions) with any existing
|
||
code.</p>
|
||
<p>An example of having “async def” and “async” attribute in one piece of
|
||
code:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Spam</span><span class="p">:</span>
|
||
<span class="k">async</span> <span class="o">=</span> <span class="mi">42</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">ham</span><span class="p">():</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">Spam</span><span class="p">,</span> <span class="s1">'async'</span><span class="p">))</span>
|
||
|
||
<span class="c1"># The coroutine can be executed and will print '42'</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="backwards-compatibility">
|
||
<h3><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h3>
|
||
<p>This proposal preserves 100% backwards compatibility.</p>
|
||
<section id="asyncio">
|
||
<h4><a class="toc-backref" href="#asyncio" role="doc-backlink">asyncio</a></h4>
|
||
<p><code class="docutils literal notranslate"><span class="pre">asyncio</span></code> module was adapted and tested to work with coroutines and
|
||
new statements. Backwards compatibility is 100% preserved, i.e. all
|
||
existing code will work as-is.</p>
|
||
<p>The required changes are mainly:</p>
|
||
<ol class="arabic simple">
|
||
<li>Modify <code class="docutils literal notranslate"><span class="pre">@asyncio.coroutine</span></code> decorator to use new
|
||
<code class="docutils literal notranslate"><span class="pre">types.coroutine()</span></code> function.</li>
|
||
<li>Add <code class="docutils literal notranslate"><span class="pre">__await__</span> <span class="pre">=</span> <span class="pre">__iter__</span></code> line to <code class="docutils literal notranslate"><span class="pre">asyncio.Future</span></code> class.</li>
|
||
<li>Add <code class="docutils literal notranslate"><span class="pre">ensure_future()</span></code> as an alias for <code class="docutils literal notranslate"><span class="pre">async()</span></code> function.
|
||
Deprecate <code class="docutils literal notranslate"><span class="pre">async()</span></code> function.</li>
|
||
</ol>
|
||
</section>
|
||
<section id="asyncio-migration-strategy">
|
||
<h4><a class="toc-backref" href="#asyncio-migration-strategy" role="doc-backlink">asyncio migration strategy</a></h4>
|
||
<p>Because <em>plain generators</em> cannot <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> <em>native coroutine
|
||
objects</em> (see <a class="reference internal" href="#differences-from-generators">Differences from generators</a> section for more details),
|
||
it is advised to make sure that all generator-based coroutines are
|
||
decorated with <code class="docutils literal notranslate"><span class="pre">@asyncio.coroutine</span></code> <em>before</em> starting to use the new
|
||
syntax.</p>
|
||
</section>
|
||
<section id="async-await-in-cpython-code-base">
|
||
<h4><a class="toc-backref" href="#async-await-in-cpython-code-base" role="doc-backlink">async/await in CPython code base</a></h4>
|
||
<p>There is no use of <code class="docutils literal notranslate"><span class="pre">await</span></code> names in CPython.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">async</span></code> is mostly used by asyncio. We are addressing this by
|
||
renaming <code class="docutils literal notranslate"><span class="pre">async()</span></code> function to <code class="docutils literal notranslate"><span class="pre">ensure_future()</span></code> (see <a class="reference internal" href="#asyncio">asyncio</a>
|
||
section for details).</p>
|
||
<p>Another use of <code class="docutils literal notranslate"><span class="pre">async</span></code> keyword is in <code class="docutils literal notranslate"><span class="pre">Lib/xml/dom/xmlbuilder.py</span></code>,
|
||
to define an <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">=</span> <span class="pre">False</span></code> attribute for <code class="docutils literal notranslate"><span class="pre">DocumentLS</span></code> class.
|
||
There is no documentation or tests for it, it is not used anywhere else
|
||
in CPython. It is replaced with a getter, that raises a
|
||
<code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code>, advising to use <code class="docutils literal notranslate"><span class="pre">async_</span></code> attribute instead.
|
||
‘async’ attribute is not documented and is not used in CPython code
|
||
base.</p>
|
||
</section>
|
||
</section>
|
||
<section id="grammar-updates">
|
||
<h3><a class="toc-backref" href="#grammar-updates" role="doc-backlink">Grammar Updates</a></h3>
|
||
<p>Grammar changes are fairly minimal:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">decorated</span><span class="p">:</span> <span class="n">decorators</span> <span class="p">(</span><span class="n">classdef</span> <span class="o">|</span> <span class="n">funcdef</span> <span class="o">|</span> <span class="n">async_funcdef</span><span class="p">)</span>
|
||
<span class="n">async_funcdef</span><span class="p">:</span> <span class="n">ASYNC</span> <span class="n">funcdef</span>
|
||
|
||
<span class="n">compound_stmt</span><span class="p">:</span> <span class="p">(</span><span class="n">if_stmt</span> <span class="o">|</span> <span class="n">while_stmt</span> <span class="o">|</span> <span class="n">for_stmt</span> <span class="o">|</span> <span class="n">try_stmt</span> <span class="o">|</span> <span class="n">with_stmt</span>
|
||
<span class="o">|</span> <span class="n">funcdef</span> <span class="o">|</span> <span class="n">classdef</span> <span class="o">|</span> <span class="n">decorated</span> <span class="o">|</span> <span class="n">async_stmt</span><span class="p">)</span>
|
||
|
||
<span class="n">async_stmt</span><span class="p">:</span> <span class="n">ASYNC</span> <span class="p">(</span><span class="n">funcdef</span> <span class="o">|</span> <span class="n">with_stmt</span> <span class="o">|</span> <span class="n">for_stmt</span><span class="p">)</span>
|
||
|
||
<span class="n">power</span><span class="p">:</span> <span class="n">atom_expr</span> <span class="p">[</span><span class="s1">'**'</span> <span class="n">factor</span><span class="p">]</span>
|
||
<span class="n">atom_expr</span><span class="p">:</span> <span class="p">[</span><span class="n">AWAIT</span><span class="p">]</span> <span class="n">atom</span> <span class="n">trailer</span><span class="o">*</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="deprecation-plans">
|
||
<h3><a class="toc-backref" href="#deprecation-plans" role="doc-backlink">Deprecation Plans</a></h3>
|
||
<p><code class="docutils literal notranslate"><span class="pre">async</span></code> and <code class="docutils literal notranslate"><span class="pre">await</span></code> names will be softly deprecated in CPython 3.5
|
||
and 3.6. In 3.7 we will transform them to proper keywords. Making
|
||
<code class="docutils literal notranslate"><span class="pre">async</span></code> and <code class="docutils literal notranslate"><span class="pre">await</span></code> proper keywords before 3.7 might make it harder
|
||
for people to port their code to Python 3.</p>
|
||
</section>
|
||
</section>
|
||
<section id="design-considerations">
|
||
<h2><a class="toc-backref" href="#design-considerations" role="doc-backlink">Design Considerations</a></h2>
|
||
<section id="pep-3152">
|
||
<h3><a class="toc-backref" href="#pep-3152" role="doc-backlink">PEP 3152</a></h3>
|
||
<p><a class="pep reference internal" href="../pep-3152/" title="PEP 3152 – Cofunctions">PEP 3152</a> by Gregory Ewing proposes a different mechanism for coroutines
|
||
(called “cofunctions”). Some key points:</p>
|
||
<ol class="arabic">
|
||
<li>A new keyword <code class="docutils literal notranslate"><span class="pre">codef</span></code> to declare a <em>cofunction</em>. <em>Cofunction</em> is
|
||
always a generator, even if there is no <code class="docutils literal notranslate"><span class="pre">cocall</span></code> expressions
|
||
inside it. Maps to <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> in this proposal.</li>
|
||
<li>A new keyword <code class="docutils literal notranslate"><span class="pre">cocall</span></code> to call a <em>cofunction</em>. Can only be used
|
||
inside a <em>cofunction</em>. Maps to <code class="docutils literal notranslate"><span class="pre">await</span></code> in this proposal (with
|
||
some differences, see below).</li>
|
||
<li>It is not possible to call a <em>cofunction</em> without a <code class="docutils literal notranslate"><span class="pre">cocall</span></code>
|
||
keyword.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">cocall</span></code> grammatically requires parentheses after it:<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"><</span><span class="n">existing</span> <span class="n">alternatives</span> <span class="k">for</span> <span class="n">atom</span><span class="o">></span>
|
||
<span class="n">cocall</span><span class="p">:</span> <span class="s1">'cocall'</span> <span class="n">atom</span> <span class="n">cotrailer</span><span class="o">*</span> <span class="s1">'('</span> <span class="p">[</span><span class="n">arglist</span><span class="p">]</span> <span class="s1">')'</span>
|
||
<span class="n">cotrailer</span><span class="p">:</span> <span class="s1">'['</span> <span class="n">subscriptlist</span> <span class="s1">']'</span> <span class="o">|</span> <span class="s1">'.'</span> <span class="n">NAME</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">cocall</span> <span class="pre">f(*args,</span> <span class="pre">**kwds)</span></code> is semantically equivalent to
|
||
<code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span> <span class="pre">f.__cocall__(*args,</span> <span class="pre">**kwds)</span></code>.</li>
|
||
</ol>
|
||
<p>Differences from this proposal:</p>
|
||
<ol class="arabic">
|
||
<li>There is no equivalent of <code class="docutils literal notranslate"><span class="pre">__cocall__</span></code> in this PEP, which is
|
||
called and its result is passed to <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> in the <code class="docutils literal notranslate"><span class="pre">cocall</span></code>
|
||
expression. <code class="docutils literal notranslate"><span class="pre">await</span></code> keyword expects an <em>awaitable</em> object,
|
||
validates the type, and executes <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> on it. Although,
|
||
<code class="docutils literal notranslate"><span class="pre">__await__</span></code> method is similar to <code class="docutils literal notranslate"><span class="pre">__cocall__</span></code>, but is only used
|
||
to define <em>Future-like</em> objects.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">await</span></code> is defined in almost the same way as <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> in the
|
||
grammar (it is later enforced that <code class="docutils literal notranslate"><span class="pre">await</span></code> can only be inside
|
||
<code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code>). It is possible to simply write <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">future</span></code>,
|
||
whereas <code class="docutils literal notranslate"><span class="pre">cocall</span></code> always requires parentheses.</li>
|
||
<li>To make asyncio work with <a class="pep reference internal" href="../pep-3152/" title="PEP 3152 – Cofunctions">PEP 3152</a> it would be required to modify
|
||
<code class="docutils literal notranslate"><span class="pre">@asyncio.coroutine</span></code> decorator to wrap all functions in an object
|
||
with a <code class="docutils literal notranslate"><span class="pre">__cocall__</span></code> method, or to implement <code class="docutils literal notranslate"><span class="pre">__cocall__</span></code> on
|
||
generators. To call <em>cofunctions</em> from existing generator-based
|
||
coroutines it would be required to use <code class="docutils literal notranslate"><span class="pre">costart(cofunc,</span> <span class="pre">*args,</span>
|
||
<span class="pre">**kwargs)</span></code> built-in.</li>
|
||
<li>Since it is impossible to call a <em>cofunction</em> without a <code class="docutils literal notranslate"><span class="pre">cocall</span></code>
|
||
keyword, it automatically prevents the common mistake of forgetting
|
||
to use <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code> on generator-based coroutines. This proposal
|
||
addresses this problem with a different approach, see <a class="reference internal" href="#debugging-features">Debugging
|
||
Features</a>.</li>
|
||
<li>A shortcoming of requiring a <code class="docutils literal notranslate"><span class="pre">cocall</span></code> keyword to call a coroutine
|
||
is that if is decided to implement coroutine-generators –
|
||
coroutines with <code class="docutils literal notranslate"><span class="pre">yield</span></code> or <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">yield</span></code> expressions – we
|
||
wouldn’t need a <code class="docutils literal notranslate"><span class="pre">cocall</span></code> keyword to call them. So we’ll end up
|
||
having <code class="docutils literal notranslate"><span class="pre">__cocall__</span></code> and no <code class="docutils literal notranslate"><span class="pre">__call__</span></code> for regular coroutines,
|
||
and having <code class="docutils literal notranslate"><span class="pre">__call__</span></code> and no <code class="docutils literal notranslate"><span class="pre">__cocall__</span></code> for
|
||
coroutine-generators.</li>
|
||
<li>Requiring parentheses grammatically also introduces a whole lot
|
||
of new problems.<p>The following code:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">await</span> <span class="n">fut</span>
|
||
<span class="k">await</span> <span class="n">function_returning_future</span><span class="p">()</span>
|
||
<span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="n">coro1</span><span class="p">(</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">),</span> <span class="n">coro2</span><span class="p">(</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>would look like:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cocall</span> <span class="n">fut</span><span class="p">()</span> <span class="c1"># or cocall costart(fut)</span>
|
||
<span class="n">cocall</span> <span class="p">(</span><span class="n">function_returning_future</span><span class="p">())()</span>
|
||
<span class="n">cocall</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="n">costart</span><span class="p">(</span><span class="n">coro1</span><span class="p">,</span> <span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">),</span>
|
||
<span class="n">costart</span><span class="p">(</span><span class="n">coro2</span><span class="p">,</span> <span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>There are no equivalents of <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code> and <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code> in PEP
|
||
3152.</li>
|
||
</ol>
|
||
</section>
|
||
<section id="coroutine-generators">
|
||
<h3><a class="toc-backref" href="#coroutine-generators" role="doc-backlink">Coroutine-generators</a></h3>
|
||
<p>With <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code> keyword it is desirable to have a concept of a
|
||
<em>coroutine-generator</em> – a coroutine with <code class="docutils literal notranslate"><span class="pre">yield</span></code> and <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code>
|
||
expressions. To avoid any ambiguity with regular generators, we would
|
||
likely require to have an <code class="docutils literal notranslate"><span class="pre">async</span></code> keyword before <code class="docutils literal notranslate"><span class="pre">yield</span></code>, and
|
||
<code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">yield</span> <span class="pre">from</span></code> would raise a <code class="docutils literal notranslate"><span class="pre">StopAsyncIteration</span></code> exception.</p>
|
||
<p>While it is possible to implement coroutine-generators, we believe that
|
||
they are out of scope of this proposal. It is an advanced concept that
|
||
should be carefully considered and balanced, with a non-trivial changes
|
||
in the implementation of current generator objects. This is a matter
|
||
for a separate PEP.</p>
|
||
</section>
|
||
<section id="why-async-and-await-keywords">
|
||
<h3><a class="toc-backref" href="#why-async-and-await-keywords" role="doc-backlink">Why “async” and “await” keywords</a></h3>
|
||
<p>async/await is not a new concept in programming languages:</p>
|
||
<ul class="simple">
|
||
<li>C# has it since long time ago <a class="footnote-reference brackets" href="#id35" id="id17">[5]</a>;</li>
|
||
<li>proposal to add async/await in ECMAScript 7 <a class="footnote-reference brackets" href="#id32" id="id18">[2]</a>;
|
||
see also Traceur project <a class="footnote-reference brackets" href="#id39" id="id19">[9]</a>;</li>
|
||
<li>Facebook’s Hack/HHVM <a class="footnote-reference brackets" href="#id36" id="id20">[6]</a>;</li>
|
||
<li>Google’s Dart language <a class="footnote-reference brackets" href="#id37" id="id21">[7]</a>;</li>
|
||
<li>Scala <a class="footnote-reference brackets" href="#id38" id="id22">[8]</a>;</li>
|
||
<li>proposal to add async/await to C++ <a class="footnote-reference brackets" href="#id40" id="id23">[10]</a>;</li>
|
||
<li>and many other less popular languages.</li>
|
||
</ul>
|
||
<p>This is a huge benefit, as some users already have experience with
|
||
async/await, and because it makes working with many languages in one
|
||
project easier (Python with ECMAScript 7 for instance).</p>
|
||
</section>
|
||
<section id="why-aiter-does-not-return-an-awaitable">
|
||
<h3><a class="toc-backref" href="#why-aiter-does-not-return-an-awaitable" role="doc-backlink">Why “__aiter__” does not return an awaitable</a></h3>
|
||
<p><a class="pep reference internal" href="../pep-0492/" title="PEP 492 – Coroutines with async and await syntax">PEP 492</a> was accepted in CPython 3.5.0 with <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> defined as
|
||
a method, that was expected to return an awaitable resolving to an
|
||
asynchronous iterator.</p>
|
||
<p>In 3.5.2 (as <a class="pep reference internal" href="../pep-0492/" title="PEP 492 – Coroutines with async and await syntax">PEP 492</a> was accepted on a provisional basis) the
|
||
<code class="docutils literal notranslate"><span class="pre">__aiter__</span></code> protocol was updated to return asynchronous iterators
|
||
directly.</p>
|
||
<p>The motivation behind this change is to make it possible to
|
||
implement asynchronous generators in Python. See <a class="footnote-reference brackets" href="#id49" id="id24">[19]</a> and <a class="footnote-reference brackets" href="#id50" id="id25">[20]</a> for
|
||
more details.</p>
|
||
</section>
|
||
<section id="importance-of-async-keyword">
|
||
<h3><a class="toc-backref" href="#importance-of-async-keyword" role="doc-backlink">Importance of “async” keyword</a></h3>
|
||
<p>While it is possible to just implement <code class="docutils literal notranslate"><span class="pre">await</span></code> expression and treat
|
||
all functions with at least one <code class="docutils literal notranslate"><span class="pre">await</span></code> as coroutines, this approach
|
||
makes APIs design, code refactoring and its long time support harder.</p>
|
||
<p>Let’s pretend that Python only has <code class="docutils literal notranslate"><span class="pre">await</span></code> keyword:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">useful</span><span class="p">():</span>
|
||
<span class="o">...</span>
|
||
<span class="k">await</span> <span class="n">log</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
|
||
<span class="o">...</span>
|
||
|
||
<span class="k">def</span> <span class="nf">important</span><span class="p">():</span>
|
||
<span class="k">await</span> <span class="n">useful</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If <code class="docutils literal notranslate"><span class="pre">useful()</span></code> function is refactored and someone removes all
|
||
<code class="docutils literal notranslate"><span class="pre">await</span></code> expressions from it, it would become a regular python
|
||
function, and all code that depends on it, including <code class="docutils literal notranslate"><span class="pre">important()</span></code>
|
||
would be broken. To mitigate this issue a decorator similar to
|
||
<code class="docutils literal notranslate"><span class="pre">@asyncio.coroutine</span></code> has to be introduced.</p>
|
||
</section>
|
||
<section id="why-async-def">
|
||
<h3><a class="toc-backref" href="#why-async-def" role="doc-backlink">Why “async def”</a></h3>
|
||
<p>For some people bare <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">name():</span> <span class="pre">pass</span></code> syntax might look more
|
||
appealing than <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span> <span class="pre">name():</span> <span class="pre">pass</span></code>. It is certainly easier to
|
||
type. But on the other hand, it breaks the symmetry between <code class="docutils literal notranslate"><span class="pre">async</span>
|
||
<span class="pre">def</span></code>, <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code> and <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code>, where <code class="docutils literal notranslate"><span class="pre">async</span></code> is a modifier,
|
||
stating that the statement is asynchronous. It is also more consistent
|
||
with the existing grammar.</p>
|
||
</section>
|
||
<section id="why-not-await-for-and-await-with">
|
||
<h3><a class="toc-backref" href="#why-not-await-for-and-await-with" role="doc-backlink">Why not “await for” and “await with”</a></h3>
|
||
<p><code class="docutils literal notranslate"><span class="pre">async</span></code> is an adjective, and hence it is a better choice for a
|
||
<em>statement qualifier</em> keyword. <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">for/with</span></code> would imply that
|
||
something is awaiting for a completion of a <code class="docutils literal notranslate"><span class="pre">for</span></code> or <code class="docutils literal notranslate"><span class="pre">with</span></code>
|
||
statement.</p>
|
||
</section>
|
||
<section id="why-async-def-and-not-def-async">
|
||
<h3><a class="toc-backref" href="#why-async-def-and-not-def-async" role="doc-backlink">Why “async def” and not “def async”</a></h3>
|
||
<p><code class="docutils literal notranslate"><span class="pre">async</span></code> keyword is a <em>statement qualifier</em>. A good analogy to it are
|
||
“static”, “public”, “unsafe” keywords from other languages. “async
|
||
for” is an asynchronous “for” statement, “async with” is an
|
||
asynchronous “with” statement, “async def” is an asynchronous function.</p>
|
||
<p>Having “async” after the main statement keyword might introduce some
|
||
confusion, like “for async item in iterator” can be read as “for each
|
||
asynchronous item in iterator”.</p>
|
||
<p>Having <code class="docutils literal notranslate"><span class="pre">async</span></code> keyword before <code class="docutils literal notranslate"><span class="pre">def</span></code>, <code class="docutils literal notranslate"><span class="pre">with</span></code> and <code class="docutils literal notranslate"><span class="pre">for</span></code> also
|
||
makes the language grammar simpler. And “async def” better separates
|
||
coroutines from regular functions visually.</p>
|
||
</section>
|
||
<section id="why-not-a-future-import">
|
||
<h3><a class="toc-backref" href="#why-not-a-future-import" role="doc-backlink">Why not a __future__ import</a></h3>
|
||
<p><a class="reference internal" href="#transition-plan">Transition Plan</a> section explains how tokenizer is modified to treat
|
||
<code class="docutils literal notranslate"><span class="pre">async</span></code> and <code class="docutils literal notranslate"><span class="pre">await</span></code> as keywords <em>only</em> in <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> blocks.
|
||
Hence <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> fills the role that a module level compiler
|
||
declaration like <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">async_await</span></code> would otherwise
|
||
fill.</p>
|
||
</section>
|
||
<section id="why-magic-methods-start-with-a">
|
||
<h3><a class="toc-backref" href="#why-magic-methods-start-with-a" role="doc-backlink">Why magic methods start with “a”</a></h3>
|
||
<p>New asynchronous magic methods <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code>, <code class="docutils literal notranslate"><span class="pre">__anext__</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">__aenter__</span></code>, and <code class="docutils literal notranslate"><span class="pre">__aexit__</span></code> all start with the same prefix “a”.
|
||
An alternative proposal is to use “async” prefix, so that <code class="docutils literal notranslate"><span class="pre">__anext__</span></code>
|
||
becomes <code class="docutils literal notranslate"><span class="pre">__async_next__</span></code>. However, to align new magic methods with
|
||
the existing ones, such as <code class="docutils literal notranslate"><span class="pre">__radd__</span></code> and <code class="docutils literal notranslate"><span class="pre">__iadd__</span></code> it was decided
|
||
to use a shorter version.</p>
|
||
</section>
|
||
<section id="why-not-reuse-existing-magic-names">
|
||
<h3><a class="toc-backref" href="#why-not-reuse-existing-magic-names" role="doc-backlink">Why not reuse existing magic names</a></h3>
|
||
<p>An alternative idea about new asynchronous iterators and context
|
||
managers was to reuse existing magic methods, by adding an <code class="docutils literal notranslate"><span class="pre">async</span></code>
|
||
keyword to their declarations:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CM</span><span class="p">:</span>
|
||
<span class="k">async</span> <span class="k">def</span> <span class="fm">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c1"># instead of __aenter__</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This approach has the following downsides:</p>
|
||
<ul class="simple">
|
||
<li>it would not be possible to create an object that works in both
|
||
<code class="docutils literal notranslate"><span class="pre">with</span></code> and <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code> statements;</li>
|
||
<li>it would break backwards compatibility, as nothing prohibits from
|
||
returning a Future-like objects from <code class="docutils literal notranslate"><span class="pre">__enter__</span></code> and/or
|
||
<code class="docutils literal notranslate"><span class="pre">__exit__</span></code> in Python <= 3.4;</li>
|
||
<li>one of the main points of this proposal is to make native coroutines
|
||
as simple and foolproof as possible, hence the clear separation of
|
||
the protocols.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="why-not-reuse-existing-for-and-with-statements">
|
||
<h3><a class="toc-backref" href="#why-not-reuse-existing-for-and-with-statements" role="doc-backlink">Why not reuse existing “for” and “with” statements</a></h3>
|
||
<p>The vision behind existing generator-based coroutines and this proposal
|
||
is to make it easy for users to see where the code might be suspended.
|
||
Making existing “for” and “with” statements to recognize asynchronous
|
||
iterators and context managers will inevitably create implicit suspend
|
||
points, making it harder to reason about the code.</p>
|
||
</section>
|
||
<section id="comprehensions">
|
||
<h3><a class="toc-backref" href="#comprehensions" role="doc-backlink">Comprehensions</a></h3>
|
||
<p>Syntax for asynchronous comprehensions could be provided, but this
|
||
construct is outside of the scope of this PEP.</p>
|
||
</section>
|
||
<section id="async-lambda-functions">
|
||
<h3><a class="toc-backref" href="#async-lambda-functions" role="doc-backlink">Async lambda functions</a></h3>
|
||
<p>Syntax for asynchronous lambda functions could be provided, but this
|
||
construct is outside of the scope of this PEP.</p>
|
||
</section>
|
||
</section>
|
||
<section id="performance">
|
||
<h2><a class="toc-backref" href="#performance" role="doc-backlink">Performance</a></h2>
|
||
<section id="overall-impact">
|
||
<h3><a class="toc-backref" href="#overall-impact" role="doc-backlink">Overall Impact</a></h3>
|
||
<p>This proposal introduces no observable performance impact. Here is an
|
||
output of python’s official set of benchmarks <a class="footnote-reference brackets" href="#id34" id="id26">[4]</a>:</p>
|
||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>python perf.py -r -b default ../cpython/python.exe ../cpython-aw/python.exe
|
||
|
||
[skipped]
|
||
|
||
Report on Darwin ysmac 14.3.0 Darwin Kernel Version 14.3.0:
|
||
Mon Mar 23 11:59:05 PDT 2015; root:xnu-2782.20.48~5/RELEASE_X86_64
|
||
x86_64 i386
|
||
|
||
Total CPU cores: 8
|
||
|
||
### etree_iterparse ###
|
||
Min: 0.365359 -> 0.349168: 1.05x faster
|
||
Avg: 0.396924 -> 0.379735: 1.05x faster
|
||
Significant (t=9.71)
|
||
Stddev: 0.01225 -> 0.01277: 1.0423x larger
|
||
|
||
The following not significant results are hidden, use -v to show them:
|
||
django_v2, 2to3, etree_generate, etree_parse, etree_process, fastpickle,
|
||
fastunpickle, json_dump_v2, json_load, nbody, regex_v8, tornado_http.
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="tokenizer-modifications">
|
||
<h3><a class="toc-backref" href="#tokenizer-modifications" role="doc-backlink">Tokenizer modifications</a></h3>
|
||
<p>There is no observable slowdown of parsing python files with the
|
||
modified tokenizer: parsing of one 12Mb file
|
||
(<code class="docutils literal notranslate"><span class="pre">Lib/test/test_binop.py</span></code> repeated 1000 times) takes the same amount
|
||
of time.</p>
|
||
</section>
|
||
<section id="async-await">
|
||
<h3><a class="toc-backref" href="#async-await" role="doc-backlink">async/await</a></h3>
|
||
<p>The following micro-benchmark was used to determine performance
|
||
difference between “async” functions and generators:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sys</span>
|
||
<span class="kn">import</span> <span class="nn">time</span>
|
||
|
||
<span class="k">def</span> <span class="nf">binary</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">n</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="mi">1</span>
|
||
<span class="n">l</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">binary</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
|
||
<span class="n">r</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">binary</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">l</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">r</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">abinary</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">n</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="mi">1</span>
|
||
<span class="n">l</span> <span class="o">=</span> <span class="k">await</span> <span class="n">abinary</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
|
||
<span class="n">r</span> <span class="o">=</span> <span class="k">await</span> <span class="n">abinary</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">l</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">r</span>
|
||
|
||
<span class="k">def</span> <span class="nf">timeit</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="n">depth</span><span class="p">,</span> <span class="n">repeat</span><span class="p">):</span>
|
||
<span class="n">t0</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
|
||
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">repeat</span><span class="p">):</span>
|
||
<span class="n">o</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="n">depth</span><span class="p">)</span>
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||
<span class="n">o</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
|
||
<span class="k">except</span> <span class="ne">StopIteration</span><span class="p">:</span>
|
||
<span class="k">pass</span>
|
||
<span class="n">t1</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s1">'</span><span class="si">{}</span><span class="s1">(</span><span class="si">{}</span><span class="s1">) * </span><span class="si">{}</span><span class="s1">: total </span><span class="si">{:.3f}</span><span class="s1">s'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
|
||
<span class="n">func</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span> <span class="n">depth</span><span class="p">,</span> <span class="n">repeat</span><span class="p">,</span> <span class="n">t1</span><span class="o">-</span><span class="n">t0</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The result is that there is no observable performance difference:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">binary</span><span class="p">(</span><span class="mi">19</span><span class="p">)</span> <span class="o">*</span> <span class="mi">30</span><span class="p">:</span> <span class="n">total</span> <span class="mf">53.321</span><span class="n">s</span>
|
||
<span class="n">abinary</span><span class="p">(</span><span class="mi">19</span><span class="p">)</span> <span class="o">*</span> <span class="mi">30</span><span class="p">:</span> <span class="n">total</span> <span class="mf">55.073</span><span class="n">s</span>
|
||
|
||
<span class="n">binary</span><span class="p">(</span><span class="mi">19</span><span class="p">)</span> <span class="o">*</span> <span class="mi">30</span><span class="p">:</span> <span class="n">total</span> <span class="mf">53.361</span><span class="n">s</span>
|
||
<span class="n">abinary</span><span class="p">(</span><span class="mi">19</span><span class="p">)</span> <span class="o">*</span> <span class="mi">30</span><span class="p">:</span> <span class="n">total</span> <span class="mf">51.360</span><span class="n">s</span>
|
||
|
||
<span class="n">binary</span><span class="p">(</span><span class="mi">19</span><span class="p">)</span> <span class="o">*</span> <span class="mi">30</span><span class="p">:</span> <span class="n">total</span> <span class="mf">49.438</span><span class="n">s</span>
|
||
<span class="n">abinary</span><span class="p">(</span><span class="mi">19</span><span class="p">)</span> <span class="o">*</span> <span class="mi">30</span><span class="p">:</span> <span class="n">total</span> <span class="mf">51.047</span><span class="n">s</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that depth of 19 means 1,048,575 calls.</p>
|
||
</section>
|
||
</section>
|
||
<section id="reference-implementation">
|
||
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
|
||
<p>The reference implementation can be found here: <a class="footnote-reference brackets" href="#id33" id="id27">[3]</a>.</p>
|
||
<section id="list-of-high-level-changes-and-new-protocols">
|
||
<h3><a class="toc-backref" href="#list-of-high-level-changes-and-new-protocols" role="doc-backlink">List of high-level changes and new protocols</a></h3>
|
||
<ol class="arabic simple">
|
||
<li>New syntax for defining coroutines: <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> and new <code class="docutils literal notranslate"><span class="pre">await</span></code>
|
||
keyword.</li>
|
||
<li>New <code class="docutils literal notranslate"><span class="pre">__await__</span></code> method for Future-like objects, and new
|
||
<code class="docutils literal notranslate"><span class="pre">tp_as_async.am_await</span></code> slot in <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span></code>.</li>
|
||
<li>New syntax for asynchronous context managers: <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code>. And
|
||
associated protocol with <code class="docutils literal notranslate"><span class="pre">__aenter__</span></code> and <code class="docutils literal notranslate"><span class="pre">__aexit__</span></code> methods.</li>
|
||
<li>New syntax for asynchronous iteration: <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code>. And
|
||
associated protocol with <code class="docutils literal notranslate"><span class="pre">__aiter__</span></code>, <code class="docutils literal notranslate"><span class="pre">__aexit__</span></code> and new built-in
|
||
exception <code class="docutils literal notranslate"><span class="pre">StopAsyncIteration</span></code>. New <code class="docutils literal notranslate"><span class="pre">tp_as_async.am_aiter</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">tp_as_async.am_anext</span></code> slots in <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span></code>.</li>
|
||
<li>New AST nodes: <code class="docutils literal notranslate"><span class="pre">AsyncFunctionDef</span></code>, <code class="docutils literal notranslate"><span class="pre">AsyncFor</span></code>, <code class="docutils literal notranslate"><span class="pre">AsyncWith</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">Await</span></code>.</li>
|
||
<li>New functions: <code class="docutils literal notranslate"><span class="pre">sys.set_coroutine_wrapper(callback)</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">sys.get_coroutine_wrapper()</span></code>, <code class="docutils literal notranslate"><span class="pre">types.coroutine(gen)</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">inspect.iscoroutinefunction(func)</span></code>, <code class="docutils literal notranslate"><span class="pre">inspect.iscoroutine(obj)</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">inspect.isawaitable(obj)</span></code>, <code class="docutils literal notranslate"><span class="pre">inspect.getcoroutinestate(coro)</span></code>,
|
||
and <code class="docutils literal notranslate"><span class="pre">inspect.getcoroutinelocals(coro)</span></code>.</li>
|
||
<li>New <code class="docutils literal notranslate"><span class="pre">CO_COROUTINE</span></code> and <code class="docutils literal notranslate"><span class="pre">CO_ITERABLE_COROUTINE</span></code> bit flags for code
|
||
objects.</li>
|
||
<li>New ABCs: <code class="docutils literal notranslate"><span class="pre">collections.abc.Awaitable</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">collections.abc.Coroutine</span></code>, <code class="docutils literal notranslate"><span class="pre">collections.abc.AsyncIterable</span></code>, and
|
||
<code class="docutils literal notranslate"><span class="pre">collections.abc.AsyncIterator</span></code>.</li>
|
||
<li>C API changes: new <code class="docutils literal notranslate"><span class="pre">PyCoro_Type</span></code> (exposed to Python as
|
||
<code class="docutils literal notranslate"><span class="pre">types.CoroutineType</span></code>) and <code class="docutils literal notranslate"><span class="pre">PyCoroObject</span></code>.
|
||
<code class="docutils literal notranslate"><span class="pre">PyCoro_CheckExact(*o)</span></code> to test if <code class="docutils literal notranslate"><span class="pre">o</span></code> is a <em>native coroutine</em>.</li>
|
||
</ol>
|
||
<p>While the list of changes and new things is not short, it is important
|
||
to understand, that most users will not use these features directly.
|
||
It is intended to be used in frameworks and libraries to provide users
|
||
with convenient to use and unambiguous APIs with <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">await</span></code>, <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span></code> and <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code> syntax.</p>
|
||
</section>
|
||
<section id="working-example">
|
||
<h3><a class="toc-backref" href="#working-example" role="doc-backlink">Working example</a></h3>
|
||
<p>All concepts proposed in this PEP are implemented <a class="footnote-reference brackets" href="#id33" id="id28">[3]</a> and can be
|
||
tested.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">asyncio</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">echo_server</span><span class="p">():</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s1">'Serving on localhost:8000'</span><span class="p">)</span>
|
||
<span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">start_server</span><span class="p">(</span><span class="n">handle_connection</span><span class="p">,</span>
|
||
<span class="s1">'localhost'</span><span class="p">,</span> <span class="mi">8000</span><span class="p">)</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span> <span class="nf">handle_connection</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">writer</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s1">'New connection...'</span><span class="p">)</span>
|
||
|
||
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="k">await</span> <span class="n">reader</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">8192</span><span class="p">)</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">data</span><span class="p">:</span>
|
||
<span class="k">break</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="s1">'Sending </span><span class="si">{:.10}</span><span class="s1">... back'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">data</span><span class="p">)))</span>
|
||
<span class="n">writer</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
|
||
|
||
<span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
|
||
<span class="n">loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">echo_server</span><span class="p">())</span>
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">loop</span><span class="o">.</span><span class="n">run_forever</span><span class="p">()</span>
|
||
<span class="k">finally</span><span class="p">:</span>
|
||
<span class="n">loop</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="acceptance">
|
||
<h2><a class="toc-backref" href="#acceptance" role="doc-backlink">Acceptance</a></h2>
|
||
<p><a class="pep reference internal" href="../pep-0492/" title="PEP 492 – Coroutines with async and await syntax">PEP 492</a> was accepted by Guido, Tuesday, May 5, 2015 <a class="footnote-reference brackets" href="#id44" id="id29">[14]</a>.</p>
|
||
</section>
|
||
<section id="implementation">
|
||
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
|
||
<p>The implementation is tracked in issue 24017 <a class="footnote-reference brackets" href="#id45" id="id30">[15]</a>. It was
|
||
committed on May 11, 2015.</p>
|
||
</section>
|
||
<section id="references">
|
||
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id31" role="doc-footnote">
|
||
<dt class="label" id="id31">[<a href="#id13">1</a>]</dt>
|
||
<dd><a class="reference external" href="https://docs.python.org/3/library/asyncio-task.html#asyncio.coroutine">https://docs.python.org/3/library/asyncio-task.html#asyncio.coroutine</a></aside>
|
||
<aside class="footnote brackets" id="id32" role="doc-footnote">
|
||
<dt class="label" id="id32">[2]<em> (<a href='#id1'>1</a>, <a href='#id18'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="http://wiki.ecmascript.org/doku.php?id=strawman:async_functions">http://wiki.ecmascript.org/doku.php?id=strawman:async_functions</a></aside>
|
||
<aside class="footnote brackets" id="id33" role="doc-footnote">
|
||
<dt class="label" id="id33">[3]<em> (<a href='#id27'>1</a>, <a href='#id28'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="https://github.com/1st1/cpython/tree/await">https://github.com/1st1/cpython/tree/await</a></aside>
|
||
<aside class="footnote brackets" id="id34" role="doc-footnote">
|
||
<dt class="label" id="id34">[<a href="#id26">4</a>]</dt>
|
||
<dd><a class="reference external" href="https://hg.python.org/benchmarks">https://hg.python.org/benchmarks</a></aside>
|
||
<aside class="footnote brackets" id="id35" role="doc-footnote">
|
||
<dt class="label" id="id35">[5]<em> (<a href='#id2'>1</a>, <a href='#id17'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="https://msdn.microsoft.com/en-us/library/hh191443.aspx">https://msdn.microsoft.com/en-us/library/hh191443.aspx</a></aside>
|
||
<aside class="footnote brackets" id="id36" role="doc-footnote">
|
||
<dt class="label" id="id36">[6]<em> (<a href='#id3'>1</a>, <a href='#id20'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="http://docs.hhvm.com/manual/en/hack.async.php">http://docs.hhvm.com/manual/en/hack.async.php</a></aside>
|
||
<aside class="footnote brackets" id="id37" role="doc-footnote">
|
||
<dt class="label" id="id37">[7]<em> (<a href='#id4'>1</a>, <a href='#id21'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="https://www.dartlang.org/articles/await-async/">https://www.dartlang.org/articles/await-async/</a></aside>
|
||
<aside class="footnote brackets" id="id38" role="doc-footnote">
|
||
<dt class="label" id="id38">[8]<em> (<a href='#id5'>1</a>, <a href='#id22'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="http://docs.scala-lang.org/sips/pending/async.html">http://docs.scala-lang.org/sips/pending/async.html</a></aside>
|
||
<aside class="footnote brackets" id="id39" role="doc-footnote">
|
||
<dt class="label" id="id39">[<a href="#id19">9</a>]</dt>
|
||
<dd><a class="reference external" href="https://github.com/google/traceur-compiler/wiki/LanguageFeatures#async-functions-experimental">https://github.com/google/traceur-compiler/wiki/LanguageFeatures#async-functions-experimental</a></aside>
|
||
<aside class="footnote brackets" id="id40" role="doc-footnote">
|
||
<dt class="label" id="id40">[10]<em> (<a href='#id6'>1</a>, <a href='#id23'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3722.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3722.pdf</a> (PDF)</aside>
|
||
<aside class="footnote brackets" id="id41" role="doc-footnote">
|
||
<dt class="label" id="id41">[<a href="#id14">11</a>]</dt>
|
||
<dd><a class="reference external" href="https://docs.python.org/3/reference/expressions.html#generator-iterator-methods">https://docs.python.org/3/reference/expressions.html#generator-iterator-methods</a></aside>
|
||
<aside class="footnote brackets" id="id42" role="doc-footnote">
|
||
<dt class="label" id="id42">[<a href="#id11">12</a>]</dt>
|
||
<dd><a class="reference external" href="https://docs.python.org/3/reference/expressions.html#primaries">https://docs.python.org/3/reference/expressions.html#primaries</a></aside>
|
||
<aside class="footnote brackets" id="id43" role="doc-footnote">
|
||
<dt class="label" id="id43">[<a href="#id15">13</a>]</dt>
|
||
<dd><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2015-May/139851.html">https://mail.python.org/pipermail/python-dev/2015-May/139851.html</a></aside>
|
||
<aside class="footnote brackets" id="id44" role="doc-footnote">
|
||
<dt class="label" id="id44">[<a href="#id29">14</a>]</dt>
|
||
<dd><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2015-May/139844.html">https://mail.python.org/pipermail/python-dev/2015-May/139844.html</a></aside>
|
||
<aside class="footnote brackets" id="id45" role="doc-footnote">
|
||
<dt class="label" id="id45">[<a href="#id30">15</a>]</dt>
|
||
<dd><a class="reference external" href="http://bugs.python.org/issue24017">http://bugs.python.org/issue24017</a></aside>
|
||
<aside class="footnote brackets" id="id46" role="doc-footnote">
|
||
<dt class="label" id="id46">[<a href="#id16">16</a>]</dt>
|
||
<dd><a class="reference external" href="https://github.com/python/asyncio/issues/233">https://github.com/python/asyncio/issues/233</a></aside>
|
||
<aside class="footnote brackets" id="id47" role="doc-footnote">
|
||
<dt class="label" id="id47">[<a href="#id7">17</a>]</dt>
|
||
<dd><a class="reference external" href="https://hg.python.org/cpython/rev/7a0a1a4ac639">https://hg.python.org/cpython/rev/7a0a1a4ac639</a></aside>
|
||
<aside class="footnote brackets" id="id48" role="doc-footnote">
|
||
<dt class="label" id="id48">[<a href="#id8">18</a>]</dt>
|
||
<dd><a class="reference external" href="http://bugs.python.org/issue24400">http://bugs.python.org/issue24400</a></aside>
|
||
<aside class="footnote brackets" id="id49" role="doc-footnote">
|
||
<dt class="label" id="id49">[19]<em> (<a href='#id9'>1</a>, <a href='#id24'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="http://bugs.python.org/issue27243">http://bugs.python.org/issue27243</a></aside>
|
||
<aside class="footnote brackets" id="id50" role="doc-footnote">
|
||
<dt class="label" id="id50">[20]<em> (<a href='#id10'>1</a>, <a href='#id25'>2</a>) </em></dt>
|
||
<dd><a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#async-iterators">https://docs.python.org/3/reference/datamodel.html#async-iterators</a></aside>
|
||
</aside>
|
||
</section>
|
||
<section id="acknowledgments">
|
||
<h2><a class="toc-backref" href="#acknowledgments" role="doc-backlink">Acknowledgments</a></h2>
|
||
<p>I thank Guido van Rossum, Victor Stinner, Elvis Pranskevichus, Andrew
|
||
Svetlov, Łukasz Langa, Greg Ewing, Stephen J. Turnbull, Jim J. Jewett,
|
||
Brett Cannon, Alyssa Coghlan, Steven D’Aprano, Paul Moore, Nathaniel
|
||
Smith, Ethan Furman, Stefan Behnel, Paul Sokolovsky, Victor Petrovykh,
|
||
and many others for their feedback, ideas, edits, criticism, code
|
||
reviews, and discussions around this PEP.</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-0492.rst">https://github.com/python/peps/blob/main/peps/pep-0492.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0492.rst">2023-10-11 12:05:51 GMT</a></p>
|
||
|
||
</article>
|
||
<nav id="pep-sidebar">
|
||
<h2>Contents</h2>
|
||
<ul>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#api-design-and-implementation-revisions">API Design and Implementation Revisions</a></li>
|
||
<li><a class="reference internal" href="#rationale-and-goals">Rationale and Goals</a></li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#new-coroutine-declaration-syntax">New Coroutine Declaration Syntax</a></li>
|
||
<li><a class="reference internal" href="#types-coroutine">types.coroutine()</a></li>
|
||
<li><a class="reference internal" href="#await-expression">Await Expression</a><ul>
|
||
<li><a class="reference internal" href="#updated-operator-precedence-table">Updated operator precedence table</a></li>
|
||
<li><a class="reference internal" href="#examples-of-await-expressions">Examples of “await” expressions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#asynchronous-context-managers-and-async-with">Asynchronous Context Managers and “async with”</a><ul>
|
||
<li><a class="reference internal" href="#new-syntax">New Syntax</a></li>
|
||
<li><a class="reference internal" href="#example">Example</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#asynchronous-iterators-and-async-for">Asynchronous Iterators and “async for”</a><ul>
|
||
<li><a class="reference internal" href="#id12">New Syntax</a></li>
|
||
<li><a class="reference internal" href="#example-1">Example 1</a></li>
|
||
<li><a class="reference internal" href="#example-2">Example 2</a></li>
|
||
<li><a class="reference internal" href="#why-stopasynciteration">Why StopAsyncIteration?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#coroutine-objects">Coroutine objects</a><ul>
|
||
<li><a class="reference internal" href="#differences-from-generators">Differences from generators</a></li>
|
||
<li><a class="reference internal" href="#coroutine-object-methods">Coroutine object methods</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#debugging-features">Debugging Features</a></li>
|
||
<li><a class="reference internal" href="#new-standard-library-functions">New Standard Library Functions</a></li>
|
||
<li><a class="reference internal" href="#new-abstract-base-classes">New Abstract Base Classes</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#glossary">Glossary</a></li>
|
||
<li><a class="reference internal" href="#transition-plan">Transition Plan</a><ul>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
|
||
<li><a class="reference internal" href="#asyncio">asyncio</a></li>
|
||
<li><a class="reference internal" href="#asyncio-migration-strategy">asyncio migration strategy</a></li>
|
||
<li><a class="reference internal" href="#async-await-in-cpython-code-base">async/await in CPython code base</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#grammar-updates">Grammar Updates</a></li>
|
||
<li><a class="reference internal" href="#deprecation-plans">Deprecation Plans</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#design-considerations">Design Considerations</a><ul>
|
||
<li><a class="reference internal" href="#pep-3152">PEP 3152</a></li>
|
||
<li><a class="reference internal" href="#coroutine-generators">Coroutine-generators</a></li>
|
||
<li><a class="reference internal" href="#why-async-and-await-keywords">Why “async” and “await” keywords</a></li>
|
||
<li><a class="reference internal" href="#why-aiter-does-not-return-an-awaitable">Why “__aiter__” does not return an awaitable</a></li>
|
||
<li><a class="reference internal" href="#importance-of-async-keyword">Importance of “async” keyword</a></li>
|
||
<li><a class="reference internal" href="#why-async-def">Why “async def”</a></li>
|
||
<li><a class="reference internal" href="#why-not-await-for-and-await-with">Why not “await for” and “await with”</a></li>
|
||
<li><a class="reference internal" href="#why-async-def-and-not-def-async">Why “async def” and not “def async”</a></li>
|
||
<li><a class="reference internal" href="#why-not-a-future-import">Why not a __future__ import</a></li>
|
||
<li><a class="reference internal" href="#why-magic-methods-start-with-a">Why magic methods start with “a”</a></li>
|
||
<li><a class="reference internal" href="#why-not-reuse-existing-magic-names">Why not reuse existing magic names</a></li>
|
||
<li><a class="reference internal" href="#why-not-reuse-existing-for-and-with-statements">Why not reuse existing “for” and “with” statements</a></li>
|
||
<li><a class="reference internal" href="#comprehensions">Comprehensions</a></li>
|
||
<li><a class="reference internal" href="#async-lambda-functions">Async lambda functions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#performance">Performance</a><ul>
|
||
<li><a class="reference internal" href="#overall-impact">Overall Impact</a></li>
|
||
<li><a class="reference internal" href="#tokenizer-modifications">Tokenizer modifications</a></li>
|
||
<li><a class="reference internal" href="#async-await">async/await</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a><ul>
|
||
<li><a class="reference internal" href="#list-of-high-level-changes-and-new-protocols">List of high-level changes and new protocols</a></li>
|
||
<li><a class="reference internal" href="#working-example">Working example</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#acceptance">Acceptance</a></li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a></li>
|
||
<li><a class="reference internal" href="#references">References</a></li>
|
||
<li><a class="reference internal" href="#acknowledgments">Acknowledgments</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-0492.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> |