174 lines
4.4 KiB
ReStructuredText
174 lines
4.4 KiB
ReStructuredText
PEP: 530
|
|
Title: Asynchronous Comprehensions
|
|
Version: $Revision$
|
|
Last-Modified: $Date$
|
|
Author: Yury Selivanov <yury@edgedb.com>
|
|
Discussions-To: python-dev@python.org
|
|
Status: Final
|
|
Type: Standards Track
|
|
Content-Type: text/x-rst
|
|
Created: 03-Sep-2016
|
|
Python-Version: 3.6
|
|
Post-History: 03-Sep-2016
|
|
|
|
|
|
Abstract
|
|
========
|
|
|
|
:pep:`492` and :pep:`525` introduce support for native coroutines and
|
|
asynchronous generators using ``async`` / ``await`` syntax. This PEP
|
|
proposes to add asynchronous versions of list, set, dict comprehensions
|
|
and generator expressions.
|
|
|
|
|
|
Rationale and Goals
|
|
===================
|
|
|
|
Python has extensive support for synchronous comprehensions, allowing
|
|
to produce lists, dicts, and sets with a simple and concise syntax. We
|
|
propose implementing similar syntactic constructions for the
|
|
asynchronous code.
|
|
|
|
To illustrate the readability improvement, consider the following
|
|
example::
|
|
|
|
result = []
|
|
async for i in aiter():
|
|
if i % 2:
|
|
result.append(i)
|
|
|
|
With the proposed asynchronous comprehensions syntax, the above code
|
|
becomes as short as::
|
|
|
|
result = [i async for i in aiter() if i % 2]
|
|
|
|
The PEP also makes it possible to use the ``await`` expressions in
|
|
all kinds of comprehensions::
|
|
|
|
result = [await fun() for fun in funcs]
|
|
|
|
|
|
Specification
|
|
=============
|
|
|
|
Asynchronous Comprehensions
|
|
---------------------------
|
|
|
|
We propose to allow using ``async for`` inside list, set and dict
|
|
comprehensions. Pending :pep:`525` approval, we can also allow creation
|
|
of asynchronous generator expressions.
|
|
|
|
Examples:
|
|
|
|
* set comprehension: ``{i async for i in agen()}``;
|
|
|
|
* list comprehension: ``[i async for i in agen()]``;
|
|
|
|
* dict comprehension: ``{i: i ** 2 async for i in agen()}``;
|
|
|
|
* generator expression: ``(i ** 2 async for i in agen())``.
|
|
|
|
It is allowed to use ``async for`` along with ``if`` and ``for``
|
|
clauses in asynchronous comprehensions and generator expressions::
|
|
|
|
dataset = {data for line in aiter()
|
|
async for data in line
|
|
if check(data)}
|
|
|
|
Asynchronous comprehensions are only allowed inside an ``async def``
|
|
function.
|
|
|
|
In principle, asynchronous generator expressions are allowed in
|
|
any context. However, in Python 3.6, due to ``async`` and ``await``
|
|
soft-keyword status, asynchronous generator expressions are only
|
|
allowed in an ``async def`` function. Once ``async`` and ``await``
|
|
become reserved keywords in Python 3.7, this restriction will be
|
|
removed.
|
|
|
|
|
|
``await`` in Comprehensions
|
|
---------------------------
|
|
|
|
We propose to allow the use of ``await`` expressions in both
|
|
asynchronous and synchronous comprehensions::
|
|
|
|
result = [await fun() for fun in funcs]
|
|
result = {await fun() for fun in funcs}
|
|
result = {fun: await fun() for fun in funcs}
|
|
|
|
result = [await fun() for fun in funcs if await smth]
|
|
result = {await fun() for fun in funcs if await smth}
|
|
result = {fun: await fun() for fun in funcs if await smth}
|
|
|
|
result = [await fun() async for fun in funcs]
|
|
result = {await fun() async for fun in funcs}
|
|
result = {fun: await fun() async for fun in funcs}
|
|
|
|
result = [await fun() async for fun in funcs if await smth]
|
|
result = {await fun() async for fun in funcs if await smth}
|
|
result = {fun: await fun() async for fun in funcs if await smth}
|
|
|
|
This is only valid in ``async def`` function body.
|
|
|
|
|
|
Grammar Updates
|
|
---------------
|
|
|
|
The proposal requires one change on the grammar level: adding the
|
|
optional "async" keyword to ``comp_for``::
|
|
|
|
comp_for: [ASYNC] 'for' exprlist 'in' or_test [comp_iter]
|
|
|
|
The ``comprehension`` AST node will have the new ``is_async`` argument.
|
|
|
|
|
|
Backwards Compatibility
|
|
-----------------------
|
|
|
|
The proposal is fully backwards compatible.
|
|
|
|
|
|
Acceptance
|
|
==========
|
|
|
|
:pep:`530` was accepted by Guido, September 6, 2016 [1]_.
|
|
|
|
|
|
Implementation
|
|
==============
|
|
|
|
The implementation is tracked in issue 28008 [3]_. The reference
|
|
implementation git repository is available at [2]_.
|
|
|
|
|
|
References
|
|
==========
|
|
|
|
.. [1] https://mail.python.org/pipermail/python-ideas/2016-September/042141.html
|
|
|
|
.. [2] https://github.com/1st1/cpython/tree/asyncomp
|
|
|
|
.. [3] http://bugs.python.org/issue28008
|
|
|
|
|
|
Acknowledgments
|
|
===============
|
|
|
|
I thank Guido van Rossum, Victor Stinner and Elvis Pranskevichus
|
|
for their feedback, code reviews, and discussions around this
|
|
PEP.
|
|
|
|
Copyright
|
|
=========
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
..
|
|
Local Variables:
|
|
mode: indented-text
|
|
indent-tabs-mode: nil
|
|
sentence-end-double-space: t
|
|
fill-column: 70
|
|
coding: utf-8
|
|
End:
|