Python context managers — writing your own with statement
__enter__, __exit__, contextlib.contextmanager, exception suppression in __exit__, resource management pattern, practical examples
Context Managers
A context manager implements __enter__ and __exit__. with obj as x calls __enter__, runs the block, then calls __exit__ regardless of exceptions.
class Timer:
import time
def __enter__(self):
self.start = __import__("time").perf_counter()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.elapsed = __import__("time").perf_counter() - self.start
print(f"Elapsed: {self.elapsed:.4f}s")
return False # do not suppress exceptions
with Timer() as t:
total = sum(range(1_000_000))
# Elapsed: 0.0XXXs
Using contextlib
from contextlib import contextmanager
@contextmanager
def managed_file(path, mode):
f = open(path, mode)
try:
yield f
finally:
f.close()
with managed_file("out.txt", "w") as f:
f.write("hello")
Return True from __exit__ to suppress an exception; False (or None) lets it propagate. The @contextmanager decorator lets you write a context manager as a generator — put setup before yield and teardown after.
The context manager pattern solves the setup/teardown problem universally. Database connections, locks, network sockets, temporary directories, and mock patches all use it. The contextlib module provides many ready-made context managers: suppress(ExceptionType) to silently ignore specific exceptions, redirect_stdout to capture output in tests, and ExitStack to manage a variable number of context managers dynamically. Writing your own is straightforward and makes resource-management code clean and reusable across your entire codebase.
The @contextmanager decorator is the quickest way to create a context manager without a full class. Put setup code before yield and teardown in a finally block after it — the finally guarantees teardown even when an exception propagates through the with block. Context managers are also composable: with open(a) as f1, open(b) as f2: manages both files in one statement, equivalent to nesting two with blocks.
