Issue
I just noticed something surprising. Consider the following example:
import asyncio
async def wait_n(n):
asyncio.sleep(n)
async def main(fn):
print("meh")
await fn(1)
print("foo")
loop = asyncio.get_event_loop()
loop.run_until_complete(main(wait_n))
When we run this, we rightfully receive the following warning:
awaitable_lambda.py:5: RuntimeWarning: coroutine 'sleep' was never awaited
asyncio.sleep(n)
This is because in wait_n
we called asyncio.sleep(n)
without await
.
But now consider the second example:
import asyncio
async def main(fn):
print("meh")
await fn(1)
print("foo")
loop = asyncio.get_event_loop()
loop.run_until_complete(main(lambda n: asyncio.sleep(n)))
This time we are using a lambda
and surprisingly the code works just fine even though there is no await
.
I understand that we can not use await
inside a Python lambda
expression so this seems like a feature to improve ergonomics but it leads to me some questions:
- How exactly does this work? Does this simple "inject" an
await
before any coroutine function? - Is this documented somewhere (PEP)?
- Are there any other implications of this? Can we just safely call coroutinefunctions from lambda expressions and rely on Python to await things for us?
Solution
Any asynchronous function returns an awaitable. You don't need to "await
the function call" immediately, you just need to await
the returned awaitable value eventually. I.e., these two are equivalent:
await asyncio.sleep(1)
awaitable = asyncio.sleep(1)
await awaitable
As such, it should be easy to see that the call fn(1)
of the lambda (implicitly) returns an awaitable, and await
awaits it. The async def wait_n
on the other hand never returns the sleep
awaitable and never awaits it itself.
As a corollary example of this, if you have any wrapper around an async
function, there's not necessarily a need for that wrapper to be async
itself:
def add_1(func):
def wrapper(a):
return func(a + 1) # passes the awaitable return value through
return wrapper
@add_1
async def foo(a):
await asyncio.sleep(a)
async def main():
await foo(1)
Answered By - deceze
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.