Async Context Managers & Iterators
async with enters/exits awaitable setup and teardown. async for consumes async iterators that await between items - essential for streaming HTTP bodies, DB cursors, and websocket frames.
Search across all documentation pages
async with enters/exits awaitable setup and teardown. async for consumes async iterators that await between items - essential for streaming HTTP bodies, DB cursors, and websocket frames.
from contextlib import asynccontextmanager
@asynccontextmanager
async def session():
print("open")
try:
yield {"ok": True}
finally:
print("close")When to reach for this:
httpx streaming responsesimport asyncio
from contextlib import asynccontextmanager
@asynccontextmanager
async def managed_connection(name: str):
print("connect", name)
try:
yield name
finally:
print("disconnect", name)
class Countdown:
def __init__(self, start: int) -> None:
self._n = start
def __aiter__(self):
return self
async def __anext__(self) -> int:
if self._n <= 0:
raise StopAsyncIteration
await asyncio.sleep(0.01)
self._n -= 1
return self._n + 1
async def main() -> None:
async with managed_connection("db") as conn:
print("using", conn)
async for value in Countdown(3):
print("tick", value)
asyncio.run(main())What this demonstrates:
@asynccontextmanager mirrors sync contextmanager with awaitasync with calls __aenter__/__aexit__ awaitables__aiter__/__anext__ power async forStopAsyncIteration ends async iteration| Protocol | Methods |
|---|---|
| Async context manager | __aenter__, __aexit__ |
| Async iterator | __aiter__, __anext__ |
| Async generator | async def with yield |
async with client.stream("GET", url) as resp:
async for chunk in resp.aiter_bytes():
process(chunk)with on async manager - does not await teardown. Fix: always async with.__aexit__ - delays cancel. Fix: await non-blocking close paths.aclose() not called on break. Fix: async with async_generator() pattern or try/finally.async for only.| Alternative | Use When | Don't Use When |
|---|---|---|
| Manual try/finally await | Tiny scripts | Reusable resource pattern |
| Sync iterator + to_thread | Legacy sync stream | Native async stream exists |
| Callback streaming | Old SDK | Modern async client available |
Decorator for simple yield/finally; class when complex state on enter/exit.
Return True to suppress - same semantics as sync managers.
async for idiomatic on protocols; manual await recv() fine for sockets with custom logic.
break triggers aclose() on async generators - verify generator handles GeneratorExit.
async with A(), B(): or AsyncExitStack from contextlib (async support).
async with aiofiles.open(...) as f: await f.read() - async file I/O.
async with session.begin(): transaction scope - see async databases page.
Drive __anext__ until StopAsyncIteration or collect via async for in pytest-asyncio.
Use try/finally inside generator; consumers should async with aclosing(gen()) (3.10+).
async for message in ws: until connection closed - handle ConnectionClosed gracefully.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026