← Back to Python

Context Managers

PythonMidpython

The Question

What are context managers and how do you implement one?

What a Strong Answer Covers

  • __enter__/__exit__
  • "cleanup on exceptions
  • "contextlib

Senior-Level Answer

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.

What Separates a 2/3 from a 3/3

2/3 — Passing but Incomplete

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.

3/3 — Strong Answer

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.

Common Mistakes

  • Thinking context managers are only for file handling -- they are the correct pattern for any paired setup/teardown
  • Not knowing the signature of __exit__ -- the three exception parameters (type, value, traceback) are required and serve a purpose
  • Forgetting that returning True from __exit__ suppresses the exception -- accidentally suppressing errors is a real bug
  • Not knowing contextlib.contextmanager -- implementing a full class for a simple generator-based context manager is unnecessary boilerplate

Follow-Up Questions

  • What happens if an exception is raised inside a with block and __exit__ returns None? — The exception propagates after __exit__ runs -- the cleanup still occurs, but the caller receives the exception.
  • How does contextlib.contextmanager handle exceptions from inside the with block? — The exception is thrown into the generator at the yield point via generator.throw(). Wrap yield in try/except to handle it; if unhandled, it propagates.
  • What is a nested with statement and how can you simplify it? — Python 3.1+ allows multiple context managers in a single with statement using a comma -- equivalent to nested with blocks.
  • What is an async context manager? — Uses __aenter__ and __aexit__ (async def methods) and is entered with async with. Used for async resources like database connection pools.

Related Questions

  • GIL — What It Is and What It Protects
  • ThreadPoolExecutor & ProcessPoolExecutor
  • Decorators — Under the Hood
  • Generators & yield
  • LEGB Rule

Can You Explain This Cold?

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
GrindQuestionsAITechnical interview assessment
TermsPrivacyAbout