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]_.
|
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
|
1. Feedback on the initial beta release of Python 3.5 resulted in a
|
||||||
of the object model supporting this PEP to more clearly separate native
|
redesign of the object model supporting this PEP to more clearly
|
||||||
coroutines from generators - rather than being a new kind of generator,
|
separate native coroutines from generators - rather than being a
|
||||||
native coroutines are now their own completely distinct type (implemented
|
new kind of generator, native coroutines are now their own
|
||||||
in [17]_).
|
completely distinct type (implemented in [17]_).
|
||||||
|
|
||||||
This change was implemented based primarily due to problems encountered
|
This change was implemented based primarily due to problems
|
||||||
attempting to integrate support for native coroutines into the Tornado web
|
encountered attempting to integrate support for native coroutines
|
||||||
server (reported in [18]_).
|
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
|
Rationale and Goals
|
||||||
|
@ -209,11 +227,6 @@ can be one of:
|
||||||
Objects with ``__await__`` method are called *Future-like* objects in
|
Objects with ``__await__`` method are called *Future-like* objects in
|
||||||
the rest of this PEP.
|
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
|
It is a ``TypeError`` if ``__await__`` returns anything but an
|
||||||
iterator.
|
iterator.
|
||||||
|
|
||||||
|
@ -428,7 +441,7 @@ iteration:
|
||||||
|
|
||||||
1. An object must implement an ``__aiter__`` method (or, if defined
|
1. An object must implement an ``__aiter__`` method (or, if defined
|
||||||
with CPython C API, ``tp_as_async.am_aiter`` slot) returning an
|
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__``
|
2. An *asynchronous iterator object* must implement an ``__anext__``
|
||||||
method (or, if defined with CPython C API, ``tp_as_async.am_anext``
|
method (or, if defined with CPython C API, ``tp_as_async.am_anext``
|
||||||
|
@ -440,7 +453,7 @@ iteration:
|
||||||
An example of asynchronous iterable::
|
An example of asynchronous iterable::
|
||||||
|
|
||||||
class AsyncIterable:
|
class AsyncIterable:
|
||||||
async def __aiter__(self):
|
def __aiter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
async def __anext__(self):
|
async def __anext__(self):
|
||||||
|
@ -468,7 +481,7 @@ proposed::
|
||||||
which is semantically equivalent to::
|
which is semantically equivalent to::
|
||||||
|
|
||||||
iter = (ITER)
|
iter = (ITER)
|
||||||
iter = await type(iter).__aiter__(iter)
|
iter = type(iter).__aiter__(iter)
|
||||||
running = True
|
running = True
|
||||||
while running:
|
while running:
|
||||||
try:
|
try:
|
||||||
|
@ -510,7 +523,7 @@ The following code illustrates new asynchronous iteration protocol::
|
||||||
async def _prefetch(self):
|
async def _prefetch(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
async def __aiter__(self):
|
def __aiter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
async def __anext__(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::
|
which would be equivalent to the following code::
|
||||||
|
|
||||||
i = await Cursor().__aiter__()
|
i = Cursor().__aiter__()
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
row = await i.__anext__()
|
row = await i.__anext__()
|
||||||
|
@ -551,7 +564,7 @@ iterators.
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
self._it = iter(obj)
|
self._it = iter(obj)
|
||||||
|
|
||||||
async def __aiter__(self):
|
def __aiter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
async def __anext__(self):
|
async def __anext__(self):
|
||||||
|
@ -814,37 +827,6 @@ Asynchronous iterator
|
||||||
`Asynchronous Iterators and "async for"`_ for details.
|
`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
|
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).
|
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
|
PEP 492 was accepted in CPython 3.5.0 with ``__aiter__`` defined as
|
||||||
several good reasons to make it a coroutine:
|
a method, that was expected to return an awaitable resolving to an
|
||||||
|
asynchronous iterator.
|
||||||
|
|
||||||
* as most of the ``__anext__``, ``__aenter__``, and ``__aexit__``
|
In 3.5.2 (as PEP 492 was accepted on a provisional basis) the
|
||||||
methods are coroutines, users would often make a mistake defining it
|
``__aiter__`` protocol was updated to return asynchronous iterators
|
||||||
as ``async`` anyways;
|
directly.
|
||||||
|
|
||||||
* there might be a need to run some asynchronous operations in
|
The motivation behind this change is to make it possible to
|
||||||
``__aiter__``, for instance to prepare DB queries or do some file
|
implement asynchronous generators in Python. See [19]_ for
|
||||||
operation.
|
more details.
|
||||||
|
|
||||||
|
|
||||||
Importance of "async" keyword
|
Importance of "async" keyword
|
||||||
|
@ -1171,8 +1154,8 @@ Why magic methods start with "a"
|
||||||
|
|
||||||
New asynchronous magic methods ``__aiter__``, ``__anext__``,
|
New asynchronous magic methods ``__aiter__``, ``__anext__``,
|
||||||
``__aenter__``, and ``__aexit__`` all start with the same prefix "a".
|
``__aenter__``, and ``__aexit__`` all start with the same prefix "a".
|
||||||
An alternative proposal is to use "async" prefix, so that ``__aiter__``
|
An alternative proposal is to use "async" prefix, so that ``__anext__``
|
||||||
becomes ``__async_iter__``. However, to align new magic methods with
|
becomes ``__async_next__``. However, to align new magic methods with
|
||||||
the existing ones, such as ``__radd__`` and ``__iadd__`` it was decided
|
the existing ones, such as ``__radd__`` and ``__iadd__`` it was decided
|
||||||
to use a shorter version.
|
to use a shorter version.
|
||||||
|
|
||||||
|
@ -1454,6 +1437,8 @@ References
|
||||||
|
|
||||||
.. [18] http://bugs.python.org/issue24400
|
.. [18] http://bugs.python.org/issue24400
|
||||||
|
|
||||||
|
.. [19] http://bugs.python.org/issue27243
|
||||||
|
|
||||||
Acknowledgments
|
Acknowledgments
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue