pep-0492: v3; tp_await, noiter, new await syntax, etc
This commit is contained in:
parent
bca7838dae
commit
3628483783
130
pep-0492.txt
130
pep-0492.txt
|
@ -8,7 +8,7 @@ Type: Standards Track
|
||||||
Content-Type: text/x-rst
|
Content-Type: text/x-rst
|
||||||
Created: 09-Apr-2015
|
Created: 09-Apr-2015
|
||||||
Python-Version: 3.5
|
Python-Version: 3.5
|
||||||
Post-History: 17-Apr-2015, 21-Apr-2015
|
Post-History: 17-Apr-2015, 21-Apr-2015, 27-Apr-2015
|
||||||
|
|
||||||
|
|
||||||
Abstract
|
Abstract
|
||||||
|
@ -155,12 +155,40 @@ can be one of:
|
||||||
It is a ``TypeError`` if ``__await__`` returns anything but an
|
It is a ``TypeError`` if ``__await__`` returns anything but an
|
||||||
iterator.
|
iterator.
|
||||||
|
|
||||||
|
* Objects defined with CPython C API with a ``tp_await`` function,
|
||||||
|
returning an iterator (similar to ``__await__`` method).
|
||||||
|
|
||||||
It is a ``SyntaxError`` to use ``await`` outside of a coroutine.
|
It is a ``SyntaxError`` to use ``await`` outside of a coroutine.
|
||||||
|
|
||||||
It is a ``TypeError`` to pass anything other than an *awaitable* object
|
It is a ``TypeError`` to pass anything other than an *awaitable* object
|
||||||
to an ``await`` expression.
|
to an ``await`` expression.
|
||||||
|
|
||||||
|
|
||||||
|
Syntax of "await" expression
|
||||||
|
''''''''''''''''''''''''''''
|
||||||
|
|
||||||
|
``await`` keyword is defined differently from ``yield`` and ``yield
|
||||||
|
from``. The main difference is that *await expressions* do not require
|
||||||
|
parentheses around them most of the times.
|
||||||
|
|
||||||
|
Examples::
|
||||||
|
|
||||||
|
================================== ==================================
|
||||||
|
Expression Will be parsed as
|
||||||
|
================================== ==================================
|
||||||
|
``if await fut: pass`` ``if (await fut): pass``
|
||||||
|
``if await fut + 1: pass`` ``if (await fut) + 1: pass``
|
||||||
|
``pair = await fut, 'spam'`` ``pair = (await fut), 'spam'``
|
||||||
|
``with await fut, open(): pass`` ``with (await fut), open(): pass``
|
||||||
|
``await foo()['spam'].baz()()`` ``await ( foo()['spam'].baz()() )``
|
||||||
|
``return await coro()`` ``return ( await coro() )``
|
||||||
|
``res = await coro() ** 2`` ``res = (await coro()) ** 2``
|
||||||
|
``func(a1=await coro(), a2=0)`` ``func(a1=(await coro()), a2=0)``
|
||||||
|
================================== ==================================
|
||||||
|
|
||||||
|
See `Grammar Updates`_ section for details.
|
||||||
|
|
||||||
|
|
||||||
Asynchronous Context Managers and "async with"
|
Asynchronous Context Managers and "async with"
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
@ -487,6 +515,49 @@ replaces the previous wrapper. ``sys.set_coroutine_wrapper(None)``
|
||||||
unsets the wrapper.
|
unsets the wrapper.
|
||||||
|
|
||||||
|
|
||||||
|
inspect.iscoroutine() and inspect.iscoroutineobject()
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
Two new functions are added to the ``inspect`` module:
|
||||||
|
|
||||||
|
* ``inspect.iscoroutine(obj)`` returns ``True`` if ``obj`` is a
|
||||||
|
coroutine object.
|
||||||
|
|
||||||
|
* ``inspect.iscoroutinefunction(obj)`` returns ``True`` is ``obj`` is a
|
||||||
|
coroutine function.
|
||||||
|
|
||||||
|
|
||||||
|
Differences between coroutines and generators
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
A great effort has been made to make sure that coroutines and
|
||||||
|
generators are separate concepts:
|
||||||
|
|
||||||
|
1. Coroutine objects do not implement ``__iter__`` and ``__next__``
|
||||||
|
methods. Therefore they cannot be iterated over or passed to
|
||||||
|
``iter()``, ``list()``, ``tuple()`` and other built-ins. They
|
||||||
|
also cannot be used in a ``for..in`` loop.
|
||||||
|
|
||||||
|
2. ``yield from`` does not accept coroutine objects (unless it is used
|
||||||
|
in a generator-based coroutine decorated with ``types.coroutine``.)
|
||||||
|
|
||||||
|
3. ``yield from`` does not accept coroutine objects from plain Python
|
||||||
|
generators (*not* generator-based coroutines.)
|
||||||
|
|
||||||
|
4. ``inspect.isgenerator()`` and ``inspect.isgeneratorfunction()``
|
||||||
|
return ``False`` for coroutine objects and coroutine functions.
|
||||||
|
|
||||||
|
|
||||||
|
Coroutine objects
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Coroutines are based on generators internally, thus they share the
|
||||||
|
implementation. Similarly to generator objects, coroutine objects have
|
||||||
|
``throw``, ``send`` and ``close`` methods. ``StopIteration`` and
|
||||||
|
``GeneratorExit`` play the same role for coroutine objects (although
|
||||||
|
PEP 479 is enabled by default for coroutines).
|
||||||
|
|
||||||
|
|
||||||
Glossary
|
Glossary
|
||||||
========
|
========
|
||||||
|
|
||||||
|
@ -500,11 +571,12 @@ Glossary
|
||||||
details.
|
details.
|
||||||
|
|
||||||
:Future-like object:
|
:Future-like object:
|
||||||
An object with an ``__await__`` method returning an iterator. Can
|
An object with an ``__await__`` method, or a C object with
|
||||||
be consumed by an ``await`` expression in a coroutine. A coroutine
|
``tp_await`` function, returning an iterator. Can be consumed by
|
||||||
waiting for a Future-like object is suspended until the Future-like
|
an ``await`` expression in a coroutine. A coroutine waiting for a
|
||||||
object's ``__await__`` completes, and returns the result. See
|
Future-like object is suspended until the Future-like object's
|
||||||
`Await Expression`_ for details.
|
``__await__`` completes, and returns the result. See `Await
|
||||||
|
Expression`_ for details.
|
||||||
|
|
||||||
:Awaitable:
|
:Awaitable:
|
||||||
A *Future-like* object or a *coroutine object*. See `Await
|
A *Future-like* object or a *coroutine object*. See `Await
|
||||||
|
@ -602,29 +674,16 @@ Grammar Updates
|
||||||
|
|
||||||
Grammar changes are also fairly minimal::
|
Grammar changes are also fairly minimal::
|
||||||
|
|
||||||
await_expr: AWAIT test
|
|
||||||
await_stmt: await_expr
|
|
||||||
|
|
||||||
decorated: decorators (classdef | funcdef | async_funcdef)
|
decorated: decorators (classdef | funcdef | async_funcdef)
|
||||||
async_funcdef: ASYNC funcdef
|
async_funcdef: ASYNC funcdef
|
||||||
|
|
||||||
|
compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt | with_stmt
|
||||||
|
| funcdef | classdef | decorated | async_stmt)
|
||||||
|
|
||||||
async_stmt: ASYNC (funcdef | with_stmt | for_stmt)
|
async_stmt: ASYNC (funcdef | with_stmt | for_stmt)
|
||||||
|
|
||||||
compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt |
|
power: atom_expr ['**' factor]
|
||||||
with_stmt | funcdef | classdef | decorated |
|
atom_expr: [AWAIT] atom trailer*
|
||||||
async_stmt)
|
|
||||||
|
|
||||||
flow_stmt: (break_stmt | continue_stmt | return_stmt |
|
|
||||||
raise_stmt | yield_stmt | await_stmt)
|
|
||||||
|
|
||||||
atom: ('(' [yield_expr|await_expr|testlist_comp] ')' |
|
|
||||||
'[' [testlist_comp] ']' |
|
|
||||||
'{' [dictorsetmaker] '}' |
|
|
||||||
NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False’)
|
|
||||||
|
|
||||||
expr_stmt: testlist_star_expr
|
|
||||||
(augassign (yield_expr|await_expr|testlist) |
|
|
||||||
('=' (yield_expr|await_expr|testlist_star_expr))*)
|
|
||||||
|
|
||||||
|
|
||||||
Transition Period Shortcomings
|
Transition Period Shortcomings
|
||||||
|
@ -889,6 +948,15 @@ stating that the statement is asynchronous. It is also more consistent
|
||||||
with the existing grammar.
|
with the existing grammar.
|
||||||
|
|
||||||
|
|
||||||
|
Why "async for/with" instead of "await for/with"
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
``async`` is an adjective, and hence it is a better choice for a
|
||||||
|
*statement qualifier* keyword. ``await for/with`` would imply that
|
||||||
|
something is awaiting for a completion of a ``for`` or ``with``
|
||||||
|
statement.
|
||||||
|
|
||||||
|
|
||||||
Why "async def" and not "def async"
|
Why "async def" and not "def async"
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
|
@ -946,11 +1014,13 @@ This approach has the following downsides:
|
||||||
* it would not be possible to create an object that works in both
|
* it would not be possible to create an object that works in both
|
||||||
``with`` and ``async with`` statements;
|
``with`` and ``async with`` statements;
|
||||||
|
|
||||||
* it would look confusing and would require some implicit magic behind
|
* it would break backwards compatibility, as nothing prohibits from
|
||||||
the scenes in the interpreter;
|
returning a Future-like objects from ``__enter__`` and/or
|
||||||
|
``__exit__`` in Python <= 3.4;
|
||||||
|
|
||||||
* one of the main points of this proposal is to make coroutines as
|
* one of the main points of this proposal is to make coroutines as
|
||||||
simple and foolproof as possible.
|
simple and foolproof as possible, hence the clear separation of the
|
||||||
|
protocols.
|
||||||
|
|
||||||
|
|
||||||
Why not reuse existing "for" and "with" statements
|
Why not reuse existing "for" and "with" statements
|
||||||
|
@ -1074,7 +1144,8 @@ List of high-level changes and new protocols
|
||||||
1. New syntax for defining coroutines: ``async def`` and new ``await``
|
1. New syntax for defining coroutines: ``async def`` and new ``await``
|
||||||
keyword.
|
keyword.
|
||||||
|
|
||||||
2. New ``__await__`` method for Future-like objects.
|
2. New ``__await__`` method for Future-like objects, and new
|
||||||
|
``tp_await`` slot in ``PyTypeObject``.
|
||||||
|
|
||||||
3. New syntax for asynchronous context managers: ``async with``. And
|
3. New syntax for asynchronous context managers: ``async with``. And
|
||||||
associated protocol with ``__aenter__`` and ``__aexit__`` methods.
|
associated protocol with ``__aenter__`` and ``__aexit__`` methods.
|
||||||
|
@ -1087,7 +1158,8 @@ List of high-level changes and new protocols
|
||||||
``Await``.
|
``Await``.
|
||||||
|
|
||||||
6. New functions: ``sys.set_coroutine_wrapper(callback)``,
|
6. New functions: ``sys.set_coroutine_wrapper(callback)``,
|
||||||
``sys.get_coroutine_wrapper()``, and ``types.coroutine(gen)``.
|
``sys.get_coroutine_wrapper()``, ``types.coroutine(gen)``,
|
||||||
|
``inspect.iscoroutinefunction()``, and ``inspect.iscoroutine()``.
|
||||||
|
|
||||||
7. New ``CO_COROUTINE`` bit flag for code objects.
|
7. New ``CO_COROUTINE`` bit flag for code objects.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue