[Python-Dev] PEP 492 vs. PEP 3152, new round

Yury Selivanov yselivanov.ml at gmail.com
Fri Apr 24 19:50:41 CEST 2015


Guido,

On 2015-04-24 1:03 PM, Guido van Rossum wrote:
>
> *3. syntactic priority of `await`*
>
> Yury, could you tweak the syntax for `await` so that we can write the most
> common usages without parentheses? In particular I'd like to be able to
> write
> ```
> return await foo()
> with await foo() as bar: ...
> foo(await bar(), await bletch())
> ```
> (I don't care about `await foo() + await bar()` but it would be okay.)
> ```
> I think this is reasonable with some tweaks of the grammar (similar to what
> Greg did for cocall, but without requiring call syntax at the end).
I don't remember the reason why yield requires parentheses
in expressions, hopefully it's not something fundamental.
This has always annoyed me, so let's try to fix that for
await.  I'll experiment.

>
> Ditto for `__aiter__` and `__anext__`. I guess this means that the async
> equivalent to obtaining an iterator through `it = iter(xs)` followed by
> `for x over it` will have to look like `ait = await aiter(xs)` followed by
> `for x over ait`, where an iterator is required to have an `__aiter__`
> method that's an async function and returns self immediately. But what if
> you left out the `await` from the first call? I.e. can this work?
> ```
> ait = aiter(xs)
> async for x in ait:
>      print(x)

With the current semantics that PEP 492 proposes, "await"
for "aiter()" is mandatory.

You have to write

     ait = await aiter(xs)
     async for x in ait:
         print(c)

We can add some logic that will check that the iterator passed
to 'async for' is not an unresolved awaitable and resolve it
(instead of immediately checking if it has __anext__ method),
but that will complicate the implementation.  It will also
introduce more than one way of doing things.  I think that
users will recognize "async builtins" (when we add them) by
the first letter "a" and use them in "await" expressions
consistently.


> ```
> The question here is whether the object returned by aiter(xs) has an
> `__aiter__` method. Since it was intended to be the target of  `await`, it
> has an `__await__` method. But that itself is mostly an alias for
> `__iter__`, not `__aiter__`. I guess it can be made to work, the object
> just has to implement a bunch of different protocols.
Correct.  And yes, we address this all by having iteration
protocols clearly separated.

>
> *6. StopAsyncException*
>
> I'm not sure about this. The motivation given in the PEP seems to focus on
> the need for `__anext__` to be async. But is this really the right pattern?
> What if we required `ait.__anext__()` to return a future, which can either
> raise good old `StopIteration` or return the next value from the iteration
> when awaited? I'm wondering if there are a few alternatives to be explored
> around the async iterator protocol still.
__anext__ should return an awaitable (following the terminology
of the PEP), which can be a coroutine-object.  I'm not sure that
with semantics of PEP 479 it can actually raise StopIteration
(without some hacks in genobject).

I'm also trying to think forward about how we can add
generator-coroutines (the ones that combine 'await' and some
form of 'yield') to make writing asynchronous iterators
easier. I think that reusing StopIteration on that level
will be a very hard thing to understand and implement.

I'll experiment with reference implementation and update
the PEP.


Thank you,
Yury


More information about the Python-Dev mailing list