[Python-Dev] Using async/await in place of yield expression

Chris Angelico rosuav at gmail.com
Sun Nov 26 22:43:55 EST 2017


On Mon, Nov 27, 2017 at 2:20 PM, David Mertz <mertz at gnosis.cx> wrote:
> Changing subject line because this is way off to the side.  Guido and
> Nathaniel point out that you can do everything yield expressions do with
> async/await *without* an explicit event loop.  While I know that is true, it
> feels like the best case is adding fairly considerable ugliness to the code
> in the process.
>
>>
>> On Sat, Nov 25, 2017 at 3:37 PM, Guido van Rossum <guido at python.org>
>> wrote:
>> > Maybe you didn't realize async/await don't need an event loop? Driving
>> > an
>> > async/await-based coroutine is just as simple as driving a
>> > yield-from-based
>> > one (`await` does exactly the same thing as `yield from`).
>
>
>>
>> On Sun, Nov 26, 2017 at 12:29 PM, Nathaniel Smith <njs at pobox.com> wrote:
>> Technically anything you can write with yield/yield from could also be
>> written using async/await and vice-versa, but I think it's actually
>> nice to have both in the language.
>
>
> Here is some code which is definitely "toy", but follows a pattern pretty
> similar to things I really code using yield expressions:
>
> In [1]: from itertools import takewhile
> In [2]: def injectable_fib(a=1, b=2):
>    ...:     while True:
>    ...:         new = yield a
>    ...:         if new is not None:
>    ...:             a, b = new
>    ...:         a, b = b, a+b
>    ...:
> In [3]: f = injectable_fib()
> In [4]: list(takewhile(lambda x: x<200, f))
> Out[4]: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
> In [5]: f.send((100,200))
> Out[5]: 200
> In [6]: list(takewhile(lambda x: x<1000, f))
> Out[6]: [300, 500, 800]
>
>
> Imagining that 'yield' vanished from the language tomorrow, and I wanted to
> write the same thing with async/await, I think the best I can come up with
> is... actually, I just don't know who to do it without any `yield`.
>
> I can get as far as a slightly flawed:
>
> In [9]: async def atakewhile(pred, coro):
>    ...:     l = []
>    ...:     async for x in coro:
>    ...:         if pred(x):
>    ...:             return l
>    ...:         l.append(x)
>
>
> But I just have no idea what would go in the body of
>
> async def afib_injectable():
>
>
> (that is, if I'm prohibited a `yield` in there)
>

Honestly, this is one of Python's biggest problems when it comes to
async functions. I don't know the answer to that question, and I don't
know where in the docs I'd go looking for it. In JavaScript, async
functions are built on top of promises, so you can just say "well, you
return a promise, tada". But in Python, this isn't well documented.
Snooping the source code for asyncio.sleep() shows that it uses
@coroutine and yield, and I have no idea what magic @coroutine does,
nor how you'd use it without yield.

ChrisA


More information about the Python-Dev mailing list