[Python-Dev] PEP 492: __aiter__ should return async iterator directly instead of awaitable
yselivanov.ml at gmail.com
Mon Jun 6 15:23:43 EDT 2016
There is a small flaw in PEP 492 design -- __aiter__ should not return
an awaitable object that resolves to an asynchronous iterator. It should
return an asynchronous iterator directly.
Let me explain this by showing some examples.
I've discovered this while working on a new asynchronous generators
PEP. Let's pretend that we have them already: if we have a 'yield'
expression in an 'async def' function, the function becomes an
"asynchronous generator function":
async def foo():
# foo -- is an `asynchronous generator function`
# foo() -- is an `asynchronous generator`
If we iterate through "foo()", it will await on "bar()", yield "1",
await on "baz()", and yield "2":
>>> async for el in foo():
If we decide to have a class with an __aiter__ that is an async
generator, we'd write something like this:
async def __aiter__(self):
However, with the current PEP 492 design, the above code would be
invalid! The interpreter expects __aiter__ to return a coroutine, not
an async generator.
I'm still working on the PEP for async generators, targeting CPython
3.6. And once it is ready, it might still be rejected or deferred. But
in any case, this PEP 492 flaw has to be fixed now, in 3.5.2 (since PEP
492 is provisional).
I've created an issue on the bug tracker: http://bugs.python.org/issue27243
The proposed patch fixes the __aiter__ in a backwards compatible way:
1. ceval/GET_AITER opcode calls the __aiter__ method.
2. If the returned object has an '__anext__' method, GET_AITER silently
wraps it in an awaitable, which is equivalent to the following coroutine:
async def wrapper(aiter_result):
3. If the returned object does not have an '__anext__' method, a
DeprecationWarning is raised.
More information about the Python-Dev