[Python-Dev] async/await in Python; v2 (original) (raw)

Yury Selivanov yselivanov.ml at gmail.com
Wed Apr 22 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.createtask() method, and the async() function (perhaps to be renamed to ensuretask() 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