Менеджер контекста¶
Определение¶
Менеджер контекста позволяет выделять и освобождать ресурсы строго по необходимости.
В Python за это отвечает блок с оператором with. Он имеет следующую конструкцию:
Протокол контекстного менеджера¶
Контекстный менеджер должен иметь следующие методы:
- Если он синхронный - __enter__и__exit__
- Если асинхронный - __aenter__и__aexit__
В дальнейшем речь будет идти про синхронный контекстный менеджер, но ничего не мешает всё что указано ниже использовать с асинхронным контекстным менеджером (если не указано иное).
Обработка исключений¶
В случае возникновения исключения в метод __exit__ передается 3 параметра - type, value и traceback.  
При обработке исключений важно то, что возвращает метод __exit__. Тут есть 2 варианта:
- В случае, если исключение было обработано нормально метод должен вернуть True.
- Возращение любого другого значения возбудит исключение, которое передадится на уровень выше.
Контекстный менеджер из генератора¶
Здесь на помощь к нам приходит contextlib. С помощью contextmanager мы можем реализовать менеджер контекста через декоратор и генераторы. Выглядит это так:
from contextlib import contextmanager
@contextmanager
def open_file(name):
    f = open(name, 'w')
    yield f
    f.close()
Работает это следующим образом:
- Python встречает ключевое слово yield, из-за чего создается генератор, а не функция. Генератор должен возвращать только одно значение, оно будет привязано к with.
- Тот в свою очередь реализует методы __enter__и__exit__. Всё что до использования генератора попадает в__enter__, а после него - в__exit__
- В случае возникновения исключения оно вызывается внутри генератора, поэтому можно его словить и обработать при помощи конструкции `try ... except ...
Для асинхронных функций нужно использовать asynccontextmanager из того же contextlib