Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Async Context Managers | Tasks and Scheduling
Python Asyncio in Depth

Async Context Managers

Pyyhkäise näyttääksesi valikon

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:

1234567891011121314151617
import 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:

1234567891011121314151617181920212223
import 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:

123456789101112131415161718192021222324252627
import 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())
question mark

Why can't a regular with statement be used for async resources like HTTP sessions?

Valitse oikea vastaus

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 2. Luku 5

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

Osio 2. Luku 5
some-alt