An asynchronous generator produces values one at a time while awaiting asynchronous work between values. It resembles a regular generator, but its results require async for rather than for or next(). section 5.7.1
Use asynchronous generators when:
- An operation produces a sequence lazily, such as rows fetched from a database. section 5.7.1
- A large result set should be processed incrementally instead of loaded into memory all at once. section 5.6.2 section 5.7
- Each next value depends on asynchronous work; values are awaited and generated sequentially, not concurrently. section 5.7.1
Streaming database rows
With asyncpg, start a transaction, obtain a cursor for a query, and iterate with async for. The cursor yields rows incrementally, keeping only a small number in memory; its prefetch setting controls how many records are fetched ahead. section 5.7.2
Limiting the stream
Wrap an asynchronous generator in another async generator that stops after a requested count. Iterating over take(product_generator, 5) yields the first five products without materializing the complete result set. section 5.7.2
Listing 5.14 A simple asynchronous generator
import asyncio
from util import delay, async_timed
async def positive_integers_async(until: int):
for integer in range(1, until):
await delay(integer)
yield integer
@async_timed()
async def main():
async_generator = positive_integers_async(3)
print(type(async_generator))
async for number in async_generator:
print(f'Got number {number}')
asyncio.run(main())
Runnable example showing an asynchronous generator that awaits a delay, yields values, reports its async_generator type, and consumes values with async for. section 5.7.1


