Back to results for “File I/O & Context Managers”
Python › File I/O & Context Managers

How does @contextlib.contextmanager let you write a context manager using a generator function instead of a full class?

Intermediate

Answer

Decorate a generator function with @contextmanager; code BEFORE the single 'yield' runs as __enter__ (the yielded value becomes the 'as' target), and code AFTER 'yield' (typically wrapped in try/finally) runs as __exit__ — a much more concise alternative to writing a full class with two dunder methods.
from contextlib import contextmanager
import time

@contextmanager
def timer():
    start = time.time()
    try:
        yield
    finally:
        print(f"Took {time.time() - start:.2f}s")

with timer():
    do_expensive_work()
Real-world example Writing a lightweight, function-based context manager without the boilerplate of a full class-based __enter__/__exit__ implementation.

Common follow-ups: Why must the yield inside a @contextmanager-decorated generator typically be wrapped in a try/finally?