Контекстные менеджеры
Контекстный менеджер
В python есть оператор with. Размещенный внутри код выполняется с особенностью: до и после гарантированно срабатывают события входа в блок with и выхода из него. Объект, который определяет эту логику, называется контекстным менеджером.
События входа и выхода из блока определены методами __enter__ и __exit__. Первый срабатывает в тот момент, когда ход исполнения программы переходит внутрь with. Метод может вернуть значение. Оно будет доступно низлежащему внутри блока with коду.
__exit__ срабатывает в момент выхода из блока, в т.ч. и по причине исключения. В этом случае в метод будет передана тройка значений (exc_class, exc_instance, traceback).
Самый распространённый контекстный менеджер – класс, порожденный функцией open. Он гарантирует, что файл будет закрыт даже в том случае, если внутри блока возникнет ошибка.
Нужно стараться выходить из контекстного менеджера как можно быстрее, чтобы освобождать контекст и ресурсы.
Контекстные менеджеры также можно использовать для временной замены параметров, переменных окружения, транзакций БД.
with open('file.txt') as f:
data = f.read()
process_data(data)
Пример реализации своего контекстного менеджера на основе класса:
class Printable:
def __enter__(self):
print('enter')
def __exit__(self, type, value, traceback):
print('exit')
Пример реализации своего контекстного менеджера с использованием встроенной библиотеки contextlib
from contextlib import contextmanager
@contextmanager
def printable():
print('enter')
try:
yield
finally:
print('exit')
Чем можно заменить контекстный менеджер?
Можно заменить конструкцией try, finally или декоратором.
try:
# Код, который требует ресурсов
finally:
# Очистка ресурсов
def resource_manager(func):
def wrapper(*args, **kwargs):
# Инициализация ресурсов
result = func(*args, **kwargs)
# Очистка ресурсов
return result
return wrapper
@resource_manager
def expensive_operation():
# Выполнение операции
pass