Async Context Managers
Stryg for at vise menuen
You already use context managers in regular Python: with open(file) as f ensures the file is closed even if an error occurs. Async context managers work the same way – but their setup and teardown can themselves be awaitable operations.
The Problem They Solve
Opening an HTTP session, a database connection, or a file over a network involves I/O. A regular with statement can't await anything inside __enter__ and __exit__. Async context managers add __aenter__ and __aexit__ – async versions of those methods.
async with Syntax
Use async with exactly like with, but inside an async def function:
1234567891011121314151617import asyncio import httpx import nest_asyncio nest_asyncio.apply() # Opening an HTTP session as an async context manager async def fetch_user(user_id): async with httpx.AsyncClient() as client: # __aenter__ called here response = await client.get( f"https://jsonplaceholder.typicode.com/users/{user_id}" ) data = response.json() print(f"{data['name']} – {data['email']}") # __aexit__ called here – session closed automatically asyncio.run(fetch_user(1))
The httpx.AsyncClient() is an async context manager. When the async with block exits – whether normally or due to an exception – the client closes all open connections.
Writing Your Own Async Context Manager
Use @asynccontextmanager from contextlib to define one with a generator:
1234567891011121314151617181920212223import asyncio from contextlib import asynccontextmanager import nest_asyncio nest_asyncio.apply() # Simulating a database connection lifecycle @asynccontextmanager async def db_connection(db_name): print(f"Opening connection to {db_name}") await asyncio.sleep(0.1) # Simulating async connection setup try: yield db_name # The value bound to the `as` variable finally: print(f"Closing connection to {db_name}") await asyncio.sleep(0.1) # Simulating async cleanup async def main(): async with db_connection("analytics_db") as db: print(f"Running query on {db}") await asyncio.sleep(0.2) # Simulating a query asyncio.run(main())
The yield splits setup (before) from teardown (after). The finally block guarantees cleanup even if the body raises an exception.
Nesting Async Context Managers
Multiple async with statements can be combined on one line:
123456789101112131415161718192021222324252627import asyncio import httpx from contextlib import asynccontextmanager import nest_asyncio nest_asyncio.apply() # Simulating a cache connection @asynccontextmanager async def cache_connection(): print("Opening cache") await asyncio.sleep(0.05) try: yield "cache" finally: print("Closing cache") async def main(): async with httpx.AsyncClient() as client, cache_connection() as cache: response = await client.get( "https://jsonplaceholder.typicode.com/posts/1" ) data = response.json() print(f"Fetched: {data['title']}") print(f"Would cache in: {cache}") asyncio.run(main())
Tak for dine kommentarer!
Spørg AI
Spørg AI
Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat