patternpythonModeratepending
Python Async Context Managers and Generators
Viewed 0 times
async context managerasync generatoraenteraexitasynccontextmanagercleanup
Problem
Need async resource management (database connections, HTTP sessions, file handles) with proper cleanup, but the async versions of context managers and generators have subtle differences.
Solution
Async context manager and generator patterns:
import asyncio
from contextlib import asynccontextmanager
# Class-based async context manager
class AsyncDBPool:
async def __aenter__(self):
self.pool = await create_pool(dsn='...')
return self.pool
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.pool.close()
return False # Don't suppress exceptions
# Decorator-based (simpler)
@asynccontextmanager
async def get_db_connection():
conn = await asyncpg.connect('postgresql://...')
try:
yield conn
finally:
await conn.close()
# Usage
async with get_db_connection() as conn:
result = await conn.fetch('SELECT * FROM users')
# Async generator
async def fetch_pages(url):
page = 1
while True:
async with aiohttp.ClientSession() as session:
resp = await session.get(f'{url}?page={page}')
data = await resp.json()
if not data['results']:
return
yield data['results']
page += 1
# Consuming async generator
async for page in fetch_pages('https://api.example.com/items'):
for item in page:
process(item)
# Async generator with cleanup
async def watch_events():
ws = await websockets.connect('ws://...')
try:
async for msg in ws:
yield json.loads(msg)
finally:
await ws.close()Why
Async context managers ensure resources are cleaned up even when exceptions occur in async code. Without them, database connections and sockets leak under error conditions.
Gotchas
- async generators need 'async for' to consume, not regular 'for'
- Cleanup in async generators only runs if the generator is fully consumed or explicitly closed with .aclose()
Context
Managing async resources in Python
Revisions (0)
No revisions yet.