Python · The language, not just syntax
What is a context manager and how do you write one?
Short answer
A context manager defines __enter__ and __exit__ so the with statement can acquire a resource, run a block, and guarantee cleanup even when an exception occurs. contextlib.contextmanager builds one from a generator.
The with statement calls __enter__, binds its return value if there is an as target, runs the block, then calls __exit__ with exception details. __exit__ runs on normal exit and on exceptions, which is why it is the right place for closing files, releasing locks and rolling back transactions.
from contextlib import contextmanager
@contextmanager
def transaction(connection):
try:
yield connection
except Exception:
connection.rollback()
raise
else:
connection.commit()
with transaction(conn) as active:
active.execute("insert into events (kind) values (?)", ("signup",))Rules that matter
- __exit__ receives the exception type, value and traceback
- Returning True from __exit__ suppresses the exception; do this only deliberately
- Nested with statements and contextlib.ExitStack handle several resources cleanly
- A context manager is not automatically thread-safe or reentrant
The generator-based decorator is concise but easy to get wrong around exceptions. If the generator does not use try/finally, cleanup after yield may be skipped when the block raises. Explicit classes are clearer when the manager holds complex state or needs to support reentry.
Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1What arguments does __exit__ receive?
- 2How do you suppress an exception in a context manager, and when should you?
- 3What does contextlib.contextmanager do under the hood?
- 4How would you manage two resources that must be closed in reverse order?
Say it in the interview
A context manager implements __enter__ and __exit__, and the with statement guarantees __exit__ runs even if the block raises. I use it for files, locks, sockets and database transactions because cleanup must be deterministic. For simple cases I write a generator with contextlib.contextmanager and wrap the yield in try/finally. If the manager holds state or must be reentrant, I write an explicit class.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Python mock interview and get scored feedback on depth, clarity and confidence.