Context Managers in Python
Context managers manage resources by defining enter/exit semantics used by the with statement.
Using with files and locks
with ensures cleanup even if exceptions occur.
from threading import Lock
lock = Lock()
with open("data.txt", encoding="utf-8") as f:
data = f.read()
with lock:
critical_section()
Custom context managers (class)
Implement __enter__ and __exit__.
class Timer:
def __enter__(self):
import time
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc, tb):
import time
self.elapsed = time.perf_counter() - self.start
# return True to suppress exceptions (rare)
with Timer() as t:
work()
print(t.elapsed)
contextlib utilities
Use contextlib.contextmanager for simple managers made from generators.
from contextlib import contextmanager
@contextmanager
def opened(path, mode="r", **k):
f = open(path, mode, **k)
try:
yield f
finally:
f.close()
Stack managers cleanly with ExitStack.
from contextlib import ExitStack
with ExitStack() as stack:
f1 = stack.enter_context(open("a"))
f2 = stack.enter_context(open("b"))
Async context managers
async with works with objects defining __aenter__/__aexit__.
Best practices
- Keep critical sections small; avoid long‑running work inside
with - Prefer
contextlibhelpers for concise, correct managers - Avoid suppressing exceptions unless you re‑raise/log appropriately
Summary
withguarantees cleanup; write class‑ or generator‑based managers- Use
ExitStackfor dynamic sets;async withfor async resources