contextlib.contextmanager decorator

RoadmapsPython

Overview

The `@contextmanager` decorator from `contextlib` lets you build a context manager using a generator function instead of a full class with `__enter__` and `__exit__`. It breaks the generator down into three phases: - The code before the `yield` statement acts as `__enter__` (setup) - The value yielded is bound to the `as` variable - The code after the `yield` acts as `__exit__` (teardown) from contextlib import contextmanager @contextmanager def no_yield(): return # Forgot to yield! with no_yield(): pass # RuntimeError: generator didn't yield A `@contextmanager` must `yield` exactly once. Failing to `yield` raises a `RuntimeError`.

It drastically reduces boilerplate. Instead of writing a full class with dunder methods, you write a single generator function, keeping setup and teardown logic localized in one place.

Where used: `FastAPI` database sessions, Patching in unit tests, Timing execution blocks

Why learn this

Code walkthrough

from contextlib import contextmanager

@contextmanager
def log_error():
  try:
    yield
  except Exception as e:
    print(f'Logged: {e}')

with log_error():
  raise ValueError('oops')

Focus: try:\n yield

Aha moment

from contextlib import contextmanager

@contextmanager
def bad_cleanup():
  yield
  print('Cleaning')

try:
  with bad_cleanup():
    raise ValueError('Fail')
except ValueError:
  print('Caught')

Prediction: Is `'Cleaning'` printed before `'Caught'`?

Common guess: `Yes`

Because the `yield` is not wrapped in `try`/`finally`, the `ValueError` raised inside the block crashes the generator at the `yield` line. `'Cleaning'` is never reached.

Common mistakes

Glossary

generator function
A special function that can pause its execution and `yield` multiple values over time, e.g. `def f(): yield 1`.
teardown
The process of cleaning up resources, like closing a file or database connection, after they are no longer needed, e.g. `file.close()`.

Recall questions

Understanding checks

What is printed to the console?

<p> text </p>

The code before `yield` prints `<p>`, then the `with` block runs printing `text`, and finally the code after `yield` prints `</p>`.

What is printed to the console?

Start Value End

The generator yields the string `'Value'`, which gets bound to `s`. It prints `'Start'`, then `'Value'`, then `'End'`.

Practice tasks

Add Safe Teardown

Given this context manager, modify it to guarantee that `'Disconnecting'` is printed even if the `with` block raises an exception.

Challenge

A Directory Switcher

Write a context manager using `@contextmanager` called `temp_dir` that takes a dictionary and a key. It should temporarily set the key to `'temp_value'`, `yield` the new dictionary, and then restore the original value of the key afterwards.

Continue learning

Previous: __enter__ and __exit__

Previous: Function Decorators

Previous: yield keyword and generator functions

Return to Python Roadmap