asyncio: await in __await__
Objects with the __await__
method defined are called Future-like. __await__
is meant to yield a value to the loop (asyncio.Future
does exactly this).
However, you may want to await inside __await__
. The problem is, __await__
is not async
, so await
is a syntax error:
class Future:
def __await__(self):
await asyncio.sleep(1)
# await asyncio.sleep(1)
# ^
# SyntaxError: invalid syntax
You can use yield from
instead:
class Future:
def __await__(self):
yield from asyncio.sleep(1)
Another problem is, you can only yield from native coroutine in another coroutine (whether native or generator-based). __await__
is neither though:
async def sleep_one_sec():
await asyncio.sleep(1)
class Future:
def __await__(self):
yield from sleep_one_sec()
loop.run_until_complete(Future())
# 1 class Future:
# 2 def __await__(self):
#----> 3 yield from sleep_one_sec()
# 4
# TypeError: cannot 'yield from' a coroutine object
# in a non-coroutine generator
One of the solutions would be to call __await__
manually:
class Future:
def __await__(self):
yield from sleep_one_sec().__await__()
Another one is to use generator-based coroutine as an adapter:
@asyncio.coroutine
def adapter(coroutine):
yield from coroutine
class Future:
def __await__(self):
yield from adapter(sleep_one_sec())