PEP 492: Update __aiter__ protocol
This commit is contained in:
parent
b264a3e53e
commit
e6f60d8dce
113
pep-0492.txt
113
pep-0492.txt
|
@ -40,18 +40,36 @@ programming, as many other languages have adopted, or are planning to
|
|||
adopt, similar features: [2]_, [5]_, [6]_, [7]_, [8]_, [10]_.
|
||||
|
||||
|
||||
API Design and Implementation Note
|
||||
==================================
|
||||
API Design and Implementation Revisions
|
||||
=======================================
|
||||
|
||||
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 [17]_).
|
||||
1. 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 [17]_).
|
||||
|
||||
This change was implemented based primarily due to problems encountered
|
||||
attempting to integrate support for native coroutines into the Tornado web
|
||||
server (reported in [18]_).
|
||||
This change was implemented based primarily due to problems
|
||||
encountered attempting to integrate support for native coroutines
|
||||
into the Tornado web server (reported in [18]_).
|
||||
|
||||
2. In CPython 3.5.2, the ``__aiter__`` protocol was updated.
|
||||
|
||||
Before 3.5.2, ``__aiter__`` was expected to return an *awaitable*
|
||||
resolving to an *asynchronous iterator*. Starting with 3.5.2,
|
||||
``__aiter__`` should return asynchronous iterators directly.
|
||||
|
||||
If the old protocol is used in 3.5.2, Python will raise a
|
||||
``PendingDeprecationWarning``.
|
||||
|
||||
In CPython 3.6, the old ``__aiter__`` protocol will still be
|
||||
supported with a ``DeprecationWarning`` being raised.
|
||||
|
||||
In CPython 3.7, the old ``__aiter__`` protocol will no longer be
|
||||
supported: a ``RuntimeError`` will be raised if ``__aiter__``
|
||||
returns anything but an asynchronous iterator.
|
||||
|
||||
See [19]_ for more details.
|
||||
|
||||
|
||||
Rationale and Goals
|
||||
|
@ -209,11 +227,6 @@ can be one of:
|
|||
Objects with ``__await__`` method are called *Future-like* objects in
|
||||
the rest of this PEP.
|
||||
|
||||
Also, please note that ``__aiter__`` method (see its definition
|
||||
below) cannot be used for this purpose. It is a different protocol,
|
||||
and would be like using ``__iter__`` instead of ``__call__`` for
|
||||
regular callables.
|
||||
|
||||
It is a ``TypeError`` if ``__await__`` returns anything but an
|
||||
iterator.
|
||||
|
||||
|
@ -428,7 +441,7 @@ iteration:
|
|||
|
||||
1. An object must implement an ``__aiter__`` method (or, if defined
|
||||
with CPython C API, ``tp_as_async.am_aiter`` slot) returning an
|
||||
*awaitable* resulting in an *asynchronous iterator object*.
|
||||
*asynchronous iterator object*.
|
||||
|
||||
2. An *asynchronous iterator object* must implement an ``__anext__``
|
||||
method (or, if defined with CPython C API, ``tp_as_async.am_anext``
|
||||
|
@ -440,7 +453,7 @@ iteration:
|
|||
An example of asynchronous iterable::
|
||||
|
||||
class AsyncIterable:
|
||||
async def __aiter__(self):
|
||||
def __aiter__(self):
|
||||
return self
|
||||
|
||||
async def __anext__(self):
|
||||
|
@ -468,7 +481,7 @@ proposed::
|
|||
which is semantically equivalent to::
|
||||
|
||||
iter = (ITER)
|
||||
iter = await type(iter).__aiter__(iter)
|
||||
iter = type(iter).__aiter__(iter)
|
||||
running = True
|
||||
while running:
|
||||
try:
|
||||
|
@ -510,7 +523,7 @@ The following code illustrates new asynchronous iteration protocol::
|
|||
async def _prefetch(self):
|
||||
...
|
||||
|
||||
async def __aiter__(self):
|
||||
def __aiter__(self):
|
||||
return self
|
||||
|
||||
async def __anext__(self):
|
||||
|
@ -527,7 +540,7 @@ then the ``Cursor`` class can be used as follows::
|
|||
|
||||
which would be equivalent to the following code::
|
||||
|
||||
i = await Cursor().__aiter__()
|
||||
i = Cursor().__aiter__()
|
||||
while True:
|
||||
try:
|
||||
row = await i.__anext__()
|
||||
|
@ -551,7 +564,7 @@ iterators.
|
|||
def __init__(self, obj):
|
||||
self._it = iter(obj)
|
||||
|
||||
async def __aiter__(self):
|
||||
def __aiter__(self):
|
||||
return self
|
||||
|
||||
async def __anext__(self):
|
||||
|
@ -814,37 +827,6 @@ Asynchronous iterator
|
|||
`Asynchronous Iterators and "async for"`_ for details.
|
||||
|
||||
|
||||
List of functions and methods
|
||||
=============================
|
||||
|
||||
================= =================================== =================
|
||||
Method Can contain Can't contain
|
||||
================= =================================== =================
|
||||
async def func await, return value yield, yield from
|
||||
async def __a*__ await, return value yield, yield from
|
||||
def __a*__ return awaitable await
|
||||
def __await__ yield, yield from, return iterable await
|
||||
generator yield, yield from, return value await
|
||||
================= =================================== =================
|
||||
|
||||
Where:
|
||||
|
||||
* "async def func": native coroutine;
|
||||
|
||||
* "async def __a*__": ``__aiter__``, ``__anext__``, ``__aenter__``,
|
||||
``__aexit__`` defined with the ``async`` keyword;
|
||||
|
||||
* "def __a*__": ``__aiter__``, ``__anext__``, ``__aenter__``,
|
||||
``__aexit__`` defined without the ``async`` keyword, must return an
|
||||
*awaitable*;
|
||||
|
||||
* "def __await__": ``__await__`` method to implement *Future-like*
|
||||
objects;
|
||||
|
||||
* generator: a "regular" generator, function defined with ``def`` and
|
||||
which contains a least one ``yield`` or ``yield from`` expression.
|
||||
|
||||
|
||||
Transition Plan
|
||||
===============
|
||||
|
||||
|
@ -1080,19 +1062,20 @@ async/await, and because it makes working with many languages in one
|
|||
project easier (Python with ECMAScript 7 for instance).
|
||||
|
||||
|
||||
Why "__aiter__" returns awaitable
|
||||
---------------------------------
|
||||
Why "__aiter__" does not return an awaitable
|
||||
--------------------------------------------
|
||||
|
||||
In principle, ``__aiter__`` could be a regular function. There are
|
||||
several good reasons to make it a coroutine:
|
||||
PEP 492 was accepted in CPython 3.5.0 with ``__aiter__`` defined as
|
||||
a method, that was expected to return an awaitable resolving to an
|
||||
asynchronous iterator.
|
||||
|
||||
* as most of the ``__anext__``, ``__aenter__``, and ``__aexit__``
|
||||
methods are coroutines, users would often make a mistake defining it
|
||||
as ``async`` anyways;
|
||||
In 3.5.2 (as PEP 492 was accepted on a provisional basis) the
|
||||
``__aiter__`` protocol was updated to return asynchronous iterators
|
||||
directly.
|
||||
|
||||
* there might be a need to run some asynchronous operations in
|
||||
``__aiter__``, for instance to prepare DB queries or do some file
|
||||
operation.
|
||||
The motivation behind this change is to make it possible to
|
||||
implement asynchronous generators in Python. See [19]_ for
|
||||
more details.
|
||||
|
||||
|
||||
Importance of "async" keyword
|
||||
|
@ -1171,8 +1154,8 @@ Why magic methods start with "a"
|
|||
|
||||
New asynchronous magic methods ``__aiter__``, ``__anext__``,
|
||||
``__aenter__``, and ``__aexit__`` all start with the same prefix "a".
|
||||
An alternative proposal is to use "async" prefix, so that ``__aiter__``
|
||||
becomes ``__async_iter__``. However, to align new magic methods with
|
||||
An alternative proposal is to use "async" prefix, so that ``__anext__``
|
||||
becomes ``__async_next__``. However, to align new magic methods with
|
||||
the existing ones, such as ``__radd__`` and ``__iadd__`` it was decided
|
||||
to use a shorter version.
|
||||
|
||||
|
@ -1454,6 +1437,8 @@ References
|
|||
|
||||
.. [18] http://bugs.python.org/issue24400
|
||||
|
||||
.. [19] http://bugs.python.org/issue27243
|
||||
|
||||
Acknowledgments
|
||||
===============
|
||||
|
||||
|
|
Loading…
Reference in New Issue