With Statement
The with statement guarantees that setup and teardown code runs reliably, even if an exception is raised. It is backed by the context manager protocol.
Basic Usage
with open("file.txt", "r") as f:
content = f.read()
# f is automatically closed here — even if an exception occurred
How It Works Internally
with EXPR as VAR:
BODY
# is equivalent to:
mgr = EXPR
VAR = mgr.__enter__()
try:
BODY
except:
if not mgr.__exit__(*sys.exc_info()):
raise
else:
mgr.__exit__(None, None, None)
Custom Context Manager (Class)
class Timer:
def __enter__(self):
import time
self._start = time.perf_counter()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
elapsed = time.perf_counter() - self._start
print(f"Elapsed: {elapsed:.4f}s")
return False # do not suppress exceptions
with Timer() as t:
result = sum(range(1_000_000))
Custom Context Manager (Generator)
contextlib.contextmanager turns a generator into a context manager — much less boilerplate.
from contextlib import contextmanager
@contextmanager
def managed_resource(name):
print(f"Acquiring {name}")
try:
yield name # value bound to `as` variable
finally:
print(f"Releasing {name}")
with managed_resource("DB connection") as res:
print(f"Using {res}")
Multiple Context Managers
# One with statement, multiple managers
with open("input.txt") as fin, open("output.txt", "w") as fout:
fout.write(fin.read())
Common Use Cases
# Files
with open("data.txt") as f: ...
# Locks (thread safety)
import threading
lock = threading.Lock()
with lock:
shared_state += 1
# Database transactions
with db.transaction():
db.execute(...)
# Temporary directory
from tempfile import TemporaryDirectory
with TemporaryDirectory() as tmpdir:
# tmpdir is deleted when the block exits
...
# Suppress specific exceptions
from contextlib import suppress
with suppress(FileNotFoundError):
os.remove("maybe_exists.txt")
# Redirect stdout
from contextlib import redirect_stdout
import io
buf = io.StringIO()
with redirect_stdout(buf):
print("captured")
output = buf.getvalue()
Key Interview Points
__exit__receives(exc_type, exc_val, traceback)— returnTrueto suppress the exception,False(orNone) to re-raise.- The
finallyclause in a@contextmanagerfunction acts as__exit__cleanup. - Prefer
withover manualtry/finallyfor resource management — it's cleaner and less error-prone. contextlib.ExitStacklets you manage a dynamic number of context managers.