Is there ever a reason to `return await ...` in python asyncio?
Given:
async def foo() -> str:
return 'bar'
What you get when calling foo
is an Awaitable
, which obviously you'd want to await
. What you need to think about is the return value of your function. You can for example do this:
def bar() -> Awaitable[str]:
return foo() # foo as defined above
There, bar
is a synchronous function but returns an Awaitable
which results in a str
.
async def bar() -> str:
return await foo()
Above, bar
itself is async
and results in an Awaitable
when called which results in a str
, same as above. There's no real difference between these two usages. Differences appear here:
async def bar() -> Awaitable[str]:
return foo()
In that example, calling bar
results in an Awaitable
which results in an Awaitable
which results in a str
; quite different. If you naïvely use the above, you'll get this kind of result:
>>> asyncio.run(bar())
<coroutine object foo at 0x108706290>
RuntimeWarning: coroutine 'foo' was never awaited
As a rule of thumb, every call to an async
must be await
ed somewhere once. If you have two async
(async def foo
and async def bar
) but no await
in bar
, then the caller of bar
must await
twice, which would be odd.
TL)DR of @deceze answer.
Yes, there is a reason. Always return await
from a coroutine when calling another coroutine.
Async
functions always return an Awaitable, even with a plain return
. You only get the actual result by calling await
. Without return await
the result is an extra wrapped Awaitable and must be awaited twice. See doc.
import asyncio
async def nested():
return 42
async def main():
# Nothing happens if we just call "nested()".
# A coroutine object is created but not awaited,
# so it *won't run at all*.
nested()
# Let's do it differently now and await it:
print(await nested()) # will print "42".
asyncio.run(main())