
Контекстные менеджеры в Python за пределами with open(): пишем свои и упрощаем код
badcasedaily1 1 минуту назад Контекстные менеджеры в Python за пределами with open(): пишем свои и упрощаем код Простой 6 мин 8 Блог компании OTUS Python * Программирование * Туториал Каждый разработчик знает with...
Вот важная новость с фронта ИИ: badcasedaily1 1 минуту назад Контекстные менеджеры в Python за пределами with open(): пишем свои и упрощаем код Простой 6 мин 8 Блог компании OTUS Python * Программирование * Туториал Каждый разработчик знает with open("file. Файл открывается, читается, закрывается автоматически, даже если внутри блока произошла ошибка. Удобно, понятно, да и безопасно.
Но почему-то with почти всегда встречается только рядом с файлами. А ведь контекстные менеджеры решают гораздо более широкий класс задач: управление соединениями с базой, транзакции, замер времени, временное изменение конфигурации, подавление ошибок, захват и освобождение ресурсов. Написать свой контекстный менеджер — дело на 5-10 строк, и код после этого становится заметно чище.
Технические детали
Что на самом деле делает withwith вызывает два метода: enter при входе в блок и exit при выходе (в том числе при исключении). Всё, что нужно от контекстного менеджера, — реализовать эти два метода:class Timer: def __enter__(self): self. perf_counter() return self def __exit__(self, exc_type, exc_val, exc_tb): self.
perf_counter() - self. start print(f"Elapsed: {self. 3f}s return False # не подавляем исключения with Timer() as t: result = expensive_computation() print(f"Computation s enter возвращает объект, который попадает в переменную после as.
exit получает информацию об исключении (если оно было) и решает, подавлять его или нет (return True подавляет, return False пробрасывает дальше). Но писать класс ради двух методов — многословно. В стандартной библиотеке есть contextlib.
Отраслевые последствия
contextmanager, который позволяет написать то же самое как генератор:from contextlib import contextmanager import time @contextmanager def timer(label: str = "Block : start = time. perf_counter() try: yield # здесь выполняется тело with-блока finally: elapsed = time. perf_counter() - start print(f"{label}: {elapsed:.
3f}s with timer("DB query : result = db. execute("SELECT * FROM orders Код до yield — это enter. Код после yield (в finally) — это exit.
Если нужно вернуть значение через as, делаете yield value. Проще, короче, и для большинства случаев достаточно. Управление соединениями с базой данныхТипичный паттерн: получить соединение из пула, выполнить работу, вернуть соединение в пул.
Событие, по словам экспертов, усилит конкуренцию в сфере ИИ.




