Skip to content
tezvyn:

Python Async Context Managers

Source: docs.python.orgHardHow cards are made

Python Async Context Managers

Async context managers let you await during setup and teardown. Use async with for database connections or streams where acquiring and releasing both need I/O. The footgun is applying @contextmanager to async cleanup, which cannot await and will crash.

Why it exists

Synchronous context managers handle cleanup with the with statement, but modern Python services spend most of their time waiting on I/O. If acquiring or releasing a resource needs an await, such as connecting to a PostgreSQL database or closing an HTTP session, the standard enter and exit methods cannot suspend execution. Blocking the event loop to perform cleanup defeats the purpose of async code. Asynchronous context managers were added so that setup and teardown could both yield control back to the event loop, letting other coroutines run while the resource waits to open or close.

The mental model

Think of a regular context manager as a light switch that you flip on and off instantly. An async context manager is like a smart home switch that must send a network command to turn the lamp on or off, and the switch returns only after the device acknowledges the signal. You still get the same try-finally guarantee, but both arms of the transaction can pause.

How it works

You create one by either implementing aenter and aexit on a class, or by decorating an async generator with @asynccontextmanager from the contextlib module. The decorated function must yield exactly one value, which becomes the bound variable in the async with statement. Code before the yield runs as setup and can await. Code after the yield, usually in a finally block, runs as teardown and can also await. If the body of the async with raises an exception, it is injected back into the generator at the yield point so you can catch or re-raise it.

When to use it

Use it whenever a resource lifecycle crosses an async boundary. Common cases include acquiring and releasing database connections, opening and flushing websocket streams, entering and exiting distributed locks over the network, or metering async API calls where rate-limit cleanup requires an HTTP request.

When not to use it

Do not use it for purely synchronous resources because the overhead of an async generator and event loop coordination is wasted if no suspension is needed. Also avoid it if you are tempted to put heavy CPU work in aenter or aexit without an await, because that still blocks the event loop. Finally, do not mix the sync @contextmanager decorator with async cleanup; that decorator is for synchronous generators only and cannot await.

One canonical example

The docs show a database connection factory. You define async def get_connection, assign conn via await acquire_db_connection, then in a try block yield conn, and in a finally block await release_db_connection on conn, decorating the function with @asynccontextmanager. A caller then writes async with get_connection as conn and runs conn.query. Even if the query raises, the finally block runs and the connection is released asynchronously.

Interview question

You write an async generator that awaits during resource teardown, but mistakenly decorate it with @contextmanager. What is the most likely result?

  • a.The event loop schedules the cleanup in a background thread to prevent blocking
  • b.A runtime error occurs because the synchronous decorator cannot await inside the generatorCorrect
  • c.The async with statement falls back to __enter__ and __exit__, silently skipping the async cleanup
  • d.Cleanup runs synchronously and blocks the event loop until the database releases the connection
Why?

The card explicitly warns that @contextmanager is for synchronous generators only and cannot await, causing a crash. Distractor A is tempting because blocking the event loop is discussed as a general risk of async code, but the specific mistake of using the sync decorator with async cleanup results in a runtime error rather than silent blocking.

Just read this? Test yourself on what you have been reading.

Read the original → docs.python.org

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on python — each one lists the topics its interview covers.

See open roles