What are context managers and how do you implement one?
A context manager is an object that defines a setup and teardown protocol for a block of code, ensuring cleanup happens reliably regardless of whether the block exits normally or via an exception. The with statement invokes this protocol.
The protocol has two methods. __enter__(self) is called when execution enters the with block; its return value is bound to the name after as (if provided). __exit__(self, exc_type, exc_val, exc_tb) is called when the block exits -- whether normally, via a return, or via an exception. If __exit__ returns a truthy value, any exception is suppressed; if it returns False or None, the exception propagates.
A class-based context manager implements both methods directly. The canonical example is a file: open() returns an object whose __enter__ returns the file handle and whose __exit__ closes the file. Database connection context managers commit the transaction in __exit__ on success and roll it back on exception. Lock context managers acquire the lock in __enter__ and release it in __exit__.
For simpler use cases, the contextlib.contextmanager decorator allows writing a context manager as a generator function. The code before yield is __enter__; the value yielded is the as target; the code after yield runs as __exit__. A try/except around the yield handles exceptions from inside the with block. This approach is more concise for one-off context managers.
Context managers are the correct pattern for any resource that needs paired setup and teardown: files, database connections, network sockets, locks, transactions, temporary directories, mocked objects in tests (unittest.mock.patch is a context manager), and timing or profiling blocks. They replace try/finally blocks and eliminate the class of bugs where cleanup code is accidentally skipped.
Contextlib provides several ready-made utilities: contextlib.suppress to suppress specific exceptions, contextlib.nullcontext as a no-op for conditional context use, and contextlib.asynccontextmanager for async context managers.
Candidate explains __enter__ and __exit__, knows the with statement protocol, and can implement a class-based context manager -- but does not know contextlib.contextmanager, how to suppress exceptions in __exit__, or async context managers.
Candidate explains both implementation approaches (class-based and contextlib.contextmanager), explains exception suppression via __exit__ return value, names realistic use cases beyond files, and mentions contextlib utilities and async context managers.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment