Встречается на 43% собеседований по Python

Что такое контекстный менеджер

Контекстный менеджер в Python — это объект, который определяет поведение при входе в блок оператора with и при выходе из него, гарантируя выполнение определенных действий (например, освобождение ресурсов) даже при возникновении исключений. Он реализует методы __enter__ и __exit__, которые вызываются автоматически в начале и в конце блока with.

Как это работает

Оператор with — это синтаксический сахар для управления ресурсами. Когда выполнение программы доходит до with, вызывается метод __enter__ контекстного менеджера. Его возвращаемое значение (если оно есть) связывается с переменной после as. После завершения блока — нормального или из-за исключения — вызывается метод __exit__. Если внутри блока возникло исключение, в __exit__ передаются три аргумента: класс исключения, экземпляр исключения и объект traceback. Метод __exit__ может вернуть True, чтобы подавить исключение, или False (или ничего), чтобы оно продолжило распространяться.

Примеры

Самый распространённый контекстный менеджер — файловый объект, возвращаемый функцией open(). Он гарантирует, что файл будет закрыт, даже если внутри блока произошла ошибка:

python
with open('file.txt') as f:
    data = f.read()
process_data(data)

Можно написать собственный контекстный менеджер на основе класса:

python
class Printable:
    def __enter__(self):
        print('enter')

    def __exit__(self, type, value, traceback):
        print('exit')

Более удобный способ — использовать декоратор @contextmanager из модуля contextlib. Функция-генератор с yield разделяет код на часть до входа и после выхода:

python
from contextlib import contextmanager

@contextmanager
def printable():
    print('enter')
    try:
        yield
    finally:
        print('exit')

Подводные камни

  • Если в __enter__ не возвращать значение, переменная после as будет равна None. Это часто забывают.
  • В __exit__ нужно корректно обрабатывать исключения: если не вернуть True, исключение будет проброшено дальше. Возврат True подавляет исключение, что может быть нежелательно.
  • Контекстный менеджер должен освобождать ресурсы как можно быстрее, чтобы не держать их дольше необходимого. Поэтому блок with стараются делать коротким.
  • При использовании @contextmanager важно оборачивать yield в try/finally, чтобы гарантировать выполнение кода после yield даже при исключении.

Когда использовать

Контекстные менеджеры применяются не только для работы с файлами. Они полезны для:

  • управления транзакциями базы данных (откат или коммит);
  • временной замены параметров или переменных окружения;
  • блокировок и мьютексов;
  • изменения текущей директории;
  • любых сценариев, где нужна гарантированная очистка ресурсов.

Коротко

  • Контекстный менеджер — объект с методами __enter__ и __exit__, используемый с оператором with.
  • __enter__ выполняется при входе в блок, __exit__ — при выходе, даже при исключении.
  • Стандартный пример — open(), гарантирующий закрытие файла.
  • Свой менеджер можно создать через класс или через @contextmanager из contextlib.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы