[Python-Dev] async/await in Python; v2

Yury Selivanov yselivanov.ml at gmail.com
Wed Apr 22 18:18:24 CEST 2015


Hi Guido,

On 2015-04-22 11:50 AM, Guido van Rossum wrote:
> On Wed, Apr 22, 2015 at 8:40 AM, Yury Selivanov <yselivanov.ml at gmail.com>
> wrote:
>> On the one hand I like your idea to disallow calling
>> coroutines without a special keyword (await in case of
>> PEP 492).  It has downsides, but there is some
>> elegance in it.  On the other hand, I hate the idea
>> of grammatically requiring parentheses for 'await'
>> expressions.  That feels non-pytonic to me.
>>
>> I'd be happy to hear others opinion on this topic.
>>
> I'm slowly warming up to Greg's notion that you can't call a coroutine (or
> whatever it's called) without a special keyword. This makes a whole class
> of bugs obvious the moment the code is executed.
>
> OTOH I'm still struggling with what you have to do to wrap a coroutine in a
> Task, the way its done in asyncio by the Task() constructor, the
> loop.create_task() method, and the async() function (perhaps to be renamed
> to ensure_task() to make way for the async keyword).
>
If we apply Greg's ideas to PEP 492 we will have the following
(Greg, correct me if I'm wrong):

1. '_typeobject' struct will get a new field 'tp_await'. We can
reuse 'tp_reserved' for that probably.

2. We'll hack Gen(/ceval.c?) objects to raise an error if they
are called directly and have a 'CO_COROUTINE' flag.

3. Task(), create_task() and async() will be modified to call
'coro.__await__(..)' if 'coro' has a 'CO_COROUTINE' flag.

4. 'await' will require parentheses grammatically. That will
make it different from 'yield' expression. For instance,
I still don't know what would 'await coro(123)()' mean.

5. 'await foo(*a, **k)' will be an equivalent to
'yield from type(coro).__await__(coro, *a, **k)'

6. If we ever decide to implement coroutine-generators --
async def functions with 'await' *and* some form of 'yield' --
we'll need to reverse the rule -- allow __call__ and
disallow __await__ on such objects (so that you'll be able
to write 'async for item in coro_gen()' instead of
'async for item in await coro_gen()'.


To be honest, that's a lot of steps and hacks to make this
concept work.  I think that 'set_coroutine_wrapper()'
solves all these problems while keeping the grammar and
implementation simpler.  Moreover, it allows to add
some additional features to the wrapped coroutines,
such as nicer repr() in debug mode (CoroWrapper in
asyncio already does that) and other runtime checks.

Thanks,
Yury


More information about the Python-Dev mailing list