Context Managers & with Interview Questions & Answers
5 questions Updated 2026-06-18
Python interview questions on context managers and the with statement, __enter__/__exit__, contextlib.contextmanager, exception handling in __exit__, and multiple context managers.
Read the in-depth guidePython Context Managers and the with Statement ExplainedA context manager is an object that defines setup and teardown logic to run
around a block of code. The with statement uses it to guarantee that the
teardown happens — even if the block raises an exception or returns early — so you
don't have to write manual try/finally.
with open("data.txt") as f: # __enter__ runs, returns the file
data = f.read()
# __exit__ runs here automatically — the file is closed
The classic use is resource management: files, network sockets, database
connections, and locks. Rule of thumb: any "acquire then must-release" pattern is
a candidate for a with block.
To make a class a context manager you implement two dunder methods. __enter__
runs at the start of the with block and its return value is bound to the as
variable. __exit__ runs when the block ends — always — receiving the
exception type, value, and traceback (all None if the block succeeded).
class Timer:
def __enter__(self):
import time; self.start = time.time()
return self # bound to 'as t'
def __exit__(self, exc_type, exc_val, exc_tb):
import time; print(time.time() - self.start)
return False # don't suppress exceptions
with Timer() as t:
do_work()
__exit__ always runs, which is what makes cleanup reliable. Rule of thumb:
acquire the resource in __enter__, release it in __exit__, and return self
if callers need the object.
The @contextlib.contextmanager decorator lets you write a context manager as a
generator instead of a class. Code before yield is the setup (__enter__),
the yielded value becomes the as target, and code after yield is the
teardown (__exit__).
from contextlib import contextmanager
@contextmanager
def opened(path):
f = open(path) # setup
try:
yield f # value bound to 'as'
finally:
f.close() # teardown — runs even on error
with opened("data.txt") as f:
print(f.read())
The try/finally around the yield is essential — without it the teardown is
skipped when the block raises. Rule of thumb: reach for the decorator for simple,
one-off managers; write a class when you need state across multiple methods.
When the with block raises, Python passes the exception details into __exit__.
The crucial part is the return value: returning a truthy value tells Python
to suppress the exception, while returning False/None lets it propagate
normally.
class Suppress:
def __enter__(self): return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is ValueError:
print("swallowed:", exc_val)
return True # suppress ValueError
return False # re-raise anything else
with Suppress():
raise ValueError("oops") # swallowed, program continues
contextlib.suppress(ValueError) is the ready-made version of this pattern. Rule
of thumb: only suppress exceptions you genuinely intend to ignore — accidentally
returning a truthy value hides bugs.
You can manage several resources in one with by separating them with commas (or
using parenthesized form in 3.10+). They are entered left to right and
exited in reverse order, so cleanup unwinds correctly.
with open("in.txt") as src, open("out.txt", "w") as dst:
dst.write(src.read())
# dst closed first, then src
import threading
lock = threading.Lock()
with lock: # acquire on enter, release on exit
shared_counter += 1
Common real uses: files (auto-close), locks (auto-release even on error),
database transactions (commit/rollback), and temporarily changing state
like decimal.localcontext. Rule of thumb: if you ever write try/finally to
release something, a context manager expresses it more clearly.
Practice tests are coming soon
Get notified when interactive mock interviews and quizzes launch.