Python etc / asyncio: yielding future

asyncio: yielding future

Once an asyncio coroutine wants to stop and communicate with the event loop, it uses await obj (or yield from obj before Python 3.6). An obj should be another coroutine, asyncio.Future or any custom Future-like object (any object with the __await__ method defined).

async def coroutine():
    await another_coroutine()

async def another_coroutine():
    future = asyncio.Future()
    await future

loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())

Once the coroutine awaits another one, the second starts to run instead of the first. If it awaits the third one, the third one runs. It goes on and on until some coroutine awaits a future. The future actually yields the value, so the loop finally gains control.

What value does the future yield? It yields itself. Can you yield a future directly? No, it's an internal detail you shouldn't normally worry about.

class Awaitable:
    def __await__(self):
        future = asyncio.Future()
        yield future
            # RuntimeError: yield was used
            # instead of yield from in task

async def coroutine():
    await Awaitable()

loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())

Why does this error occur? How does asyncio know it's you who yield the future, not the future itself There is a simple protection: the future raises the internal flag before yielding.