Менеджер контекста¶
Определение¶
Менеджер контекста позволяет выделять и освобождать ресурсы строго по необходимости.
В 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