What are Context Managers and the with Statement?
Learn how Python context managers and the with statement work, using __enter__ and __exit__ and contextlib to guarantee clean resource management with examples.
Expected Interview Answer
A context manager is an object that defines setup and teardown behavior for a block of code, used with the with statement to guarantee resources are acquired and released cleanly even if an error occurs.
The with statement calls the object's __enter__ method on entry and its __exit__ method on exit, so cleanup happens automatically regardless of how the block ends. This is why 'with open(...) as f' closes the file for you. You can build your own context managers by implementing __enter__/__exit__ on a class, or more concisely with the @contextlib.contextmanager decorator around a generator that yields once.
- Guarantees deterministic resource cleanup
- Eliminates leaked files, locks and connections
- Replaces verbose try/finally boilerplate
- Makes intent clear and code readable
- Composable and reusable across a codebase
AI Mentor Explanation
A context manager is like the ritual around a batting innings: walking out puts on the pads and gloves (__enter__), and however the innings ends — a boundary or a golden duck — you always remove the gear and return to the pavilion (__exit__). The with statement guarantees the kit is never left on the field, whatever happens at the crease.
Step-by-Step Explanation
Step 1
Open with the with statement
Write 'with expr as var:' — expr must evaluate to a context manager object.
Step 2
__enter__ runs on entry
Python calls __enter__, whose return value is bound to the name after as.
Step 3
Run the body
Execute the indented block using the acquired resource.
Step 4
__exit__ runs on exit
On leaving the block — normally or via an exception — Python calls __exit__ to clean up.
Step 5
Build your own
Implement __enter__/__exit__ on a class, or decorate a one-yield generator with @contextlib.contextmanager.
What Interviewer Expects
- Knowing __enter__ and __exit__ define the protocol
- Understanding cleanup runs even when exceptions occur
- Explaining 'with open(...)' closes the file automatically
- Building a custom context manager two ways
- Awareness that __exit__ can suppress exceptions by returning True
Common Mistakes
- Thinking with is only for opening files
- Forgetting to yield exactly once in a @contextmanager generator
- Not putting the cleanup after yield in a finally clause
- Assuming __exit__ does not run when an exception is raised
- Confusing the with statement with a regular loop or block
Best Answer (HR Friendly)
“A context manager is a helper that handles setup and cleanup for you around a block of code. The with statement uses it so things like files or database connections are always closed properly, even if something goes wrong in the middle.”
Code Example
# Built-in: file is closed automatically
with open("data.txt", "w") as f:
f.write("hello")
# f is closed here, even if write() had raised
# 1) Class-based context manager
class Timer:
def __enter__(self):
import time
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
self.elapsed = time.perf_counter() - self.start
print(f"Took {self.elapsed:.4f}s")
return False # do not suppress exceptions
with Timer():
total = sum(range(1_000_000))
# 2) Generator-based with contextlib
from contextlib import contextmanager
@contextmanager
def managed_resource(name):
print(f"acquire {name}")
try:
yield name # value bound to 'as'
finally:
print(f"release {name}")
with managed_resource("db") as res:
print(f"using {res}")Follow-up Questions
- What methods must a class implement to be a context manager?
- How does @contextlib.contextmanager work internally?
- What arguments does __exit__ receive and what does returning True do?
- How would you manage multiple resources in one with statement?
- What is contextlib.ExitStack used for?
MCQ Practice
1. Which two methods define the context manager protocol?
A context manager implements __enter__ (setup) and __exit__ (teardown), invoked by the with statement.
2. In a @contextmanager generator, where should cleanup code go?
Put cleanup in a finally block after the single yield so it runs even if the with body raises.
3. What happens to a file opened via 'with open(...) as f' when an exception occurs inside the block?
The file object's __exit__ runs on the way out even during an exception, so the file is closed.
Flash Cards
What protocol does a context manager implement? — __enter__ for setup and __exit__ for teardown, invoked by the with statement.
Why use 'with open(...)'? — It guarantees the file is closed automatically, even if the block raises an exception.
Easiest way to write a context manager? — Decorate a generator that yields once with @contextlib.contextmanager, cleanup in finally.
What does __exit__ returning True do? — It suppresses the exception raised inside the with block.