Python etc / asyncio: await in `__await__`

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())