[Python-checkins] peps: PEP 492: Update __aiter__ protocol

yury.selivanov python-checkins at python.org
Thu Jun 9 17:57:56 EDT 2016


https://hg.python.org/peps/rev/fef4b9969b9d
changeset:   6363:fef4b9969b9d
user:        Yury Selivanov <yury at magic.io>
date:        Thu Jun 09 17:57:41 2016 -0400
summary:
  PEP 492: Update __aiter__ protocol

files:
  pep-0492.txt |  113 ++++++++++++++++----------------------
  1 files changed, 49 insertions(+), 64 deletions(-)


diff --git a/pep-0492.txt b/pep-0492.txt
--- a/pep-0492.txt
+++ b/pep-0492.txt
@@ -40,18 +40,36 @@
 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 @@
   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 @@
 
 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 @@
 An example of asynchronous iterable::
 
     class AsyncIterable:
-        async def __aiter__(self):
+        def __aiter__(self):
             return self
 
         async def __anext__(self):
@@ -468,7 +481,7 @@
 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 @@
         async def _prefetch(self):
             ...
 
-        async def __aiter__(self):
+        def __aiter__(self):
             return self
 
         async def __anext__(self):
@@ -527,7 +540,7 @@
 
 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 @@
         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 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 @@
 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 @@
 
 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 @@
 
 .. [18] http://bugs.python.org/issue24400
 
+.. [19] http://bugs.python.org/issue27243
+
 Acknowledgments
 ===============
 

-- 
Repository URL: https://hg.python.org/peps


More information about the Python-checkins mailing list