Async Generators and Context Managers

1.10 · active · verified Thu Apr 09

The `async-generator` library provides a backport of asynchronous generators and asynchronous context managers to Python 3.5, which were introduced natively in Python 3.6 (PEP 525) and 3.7. It allows developers to write cleaner asynchronous code for stream processing and I/O-bound tasks using familiar generator syntax. Maintained by the Trio project, it is compatible with any async framework like asyncio or Trio. The current version is 1.10, and it is considered stable, with the last release in July 2018.

Warnings

Install

Imports

Quickstart

This example demonstrates creating an asynchronous generator with `@async_generator` and `await yield_`, an asynchronous context manager with `@asynccontextmanager`, and ensuring proper cleanup of a partially consumed async generator using `aclosing`.

import asyncio
from async_generator import async_generator, yield_, asynccontextmanager, aclosing

@async_generator
async def my_async_generator(limit):
    for i in range(limit):
        await asyncio.sleep(0.01)
        await yield_(i)

@asynccontextmanager
@async_generator
async def managed_resource():
    print("\n[SETUP] Acquiring resource...")
    resource = []
    try:
        await yield_(resource)
    finally:
        print("[TEARDOWN] Releasing resource.")
        resource.clear()

async def main():
    print("--- Using async generator ---")
    async for item in my_async_generator(3):
        print(f"Consumed: {item}")

    print("\n--- Using async context manager ---")
    async with managed_resource() as res:
        res.append("data")
        print(f"Resource in context: {res}")
    print("Resource out of context.")

    print("\n--- Generator cleanup with aclosing ---")
    gen = my_async_generator(5)
    async with aclosing(gen):
        # Consume partially
        await gen.__anext__() # Consume first item (0)
        print("Partially consumed async generator, 'aclosing' will ensure cleanup.")
    print("Generator closed via aclosing.")

if __name__ == '__main__':
    asyncio.run(main())

view raw JSON →