Вопрос проверяет понимание декоратора @contextmanager из модуля contextlib, который позволяет создавать контекстные менеджеры с помощью генераторов, упрощая управление ресурсами.
Декоратор @contextmanager — это инструмент стандартной библиотеки Python (модуль contextlib), который позволяет создавать контекстные менеджеры с использованием генераторов, избегая необходимости писать полноценный класс с методами __enter__ и __exit__. Контекстные менеджеры используются для управления ресурсами, гарантируя их корректное освобождение (например, закрытие файлов, откат транзакций).
Функция, декорированная @contextmanager, должна быть генератором и содержать ровно один yield. Код до yield выполняется при входе в блок with (аналог __enter__), а код после — при выходе из блока (аналог __exit__). Значение, возвращаемое yield, становится значением, присваиваемым переменной после as.
Рассмотрим создание контекстного менеджера для временного изменения текущей рабочей директории:
from contextlib import contextmanager
import os
@contextmanager
def temporary_cd(path):
"""Меняет директорию на время выполнения блока."""
old_dir = os.getcwd() # Код до yield — вход в контекст
os.chdir(path)
try:
yield old_dir # Значение, доступное в блоке 'as'
finally:
os.chdir(old_dir) # Код после yield — выход из контекста
# Использование
with temporary_cd('/tmp') as prev_dir:
print(f'Была директория: {prev_dir}')
print(f'Сейчас в: {os.getcwd()}')
print(f'Вернулись в: {os.getcwd()}')Код после yield выполняется всегда, даже если в блоке with возникло исключение. Для обработки исключений можно использовать try...except вокруг yield. Если исключение нужно подавить, можно использовать except и return True (как в __exit__).
Вывод: Декоратор @contextmanager стоит применять, когда нужно быстро создать простой контекстный менеджер без написания отдельного класса. Он идеален для сценариев, где управление ресурсом сводится к паре операций «установить/восстановить».