Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Context Manager Protocol (Протокол контекстного менеджера)
Контекстный менеджер — это объект, который определяет, что происходит когда вы входите и выходите из блока with. Протокол состоит из двух методов: __enter__ и __exit__.
Методы протокола
__enter__(self) — вызывается когда выполнение входит в блок with
- Может возвращать значение (которое присваивается переменной после
as) - Может выполнять инициализацию ресурсов
- Возвращаемое значение может быть
Noneили любой объект
__exit__(self, exc_type, exc_val, exc_tb) — вызывается когда выполнение выходит из блока with
exc_type— тип исключения (если оно произошло)exc_val— значение исключенияexc_tb— traceback исключения- Все параметры
Noneесли исключения не было - Возвращает
Trueесли исключение подавлено,Falseесли его нужно распространять - Обычно выполняет очистку ресурсов
Простой пример
class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
if self.file:
self.file.close()
return False # Не подавляем исключения
# Использование
with FileManager('test.txt', 'w') as f:
f.write('Hello')
# При выходе из блока вызовется __exit__ и файл закроется
Пример с обработкой исключений
class DatabaseConnection:
def __init__(self, db_name):
self.db_name = db_name
self.connection = None
def __enter__(self):
print(f"Подключение к {self.db_name}...")
self.connection = {"status": "connected"}
return self.connection
def __exit__(self, exc_type, exc_val, exc_tb):
print(f"Отключение от {self.db_name}...")
self.connection = None
if exc_type is not None:
print(f"Ошибка: {exc_type.__name__}: {exc_val}")
return False # Распространяем исключение
return True
# Использование
try:
with DatabaseConnection('mydb') as conn:
print(f"Работаем с {conn}")
raise ValueError("Что-то пошло не так")
except ValueError as e:
print(f"Поймали исключение: {e}")
Использование @contextmanager
Для простых случаев удобнее использовать декоратор из модуля contextlib:
from contextlib import contextmanager
@contextmanager
def my_context():
print("Вход")
try:
yield "ресурс" # Это вернется в блоке with
finally:
print("Выход")
with my_context() as resource:
print(f"Используем {resource}")
Асинхронные контекстные менеджеры
Для асинхронного кода используются __aenter__ и __aexit__:
class AsyncDatabaseConnection:
async def __aenter__(self):
print("Асинхронное подключение...")
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
print("Асинхронное отключение...")
return False
# Использование
async def main():
async with AsyncDatabaseConnection() as conn:
print("Работаем с асинхронным подключением")
Практические примеры в стандартной библиотеке
# Файлы
with open('file.txt') as f:
data = f.read() # __exit__ закроет файл автоматически
# Блокировки (threading)
import threading
lock = threading.Lock()
with lock: # __enter__ захватит lock, __exit__ отпустит
# критическая секция
pass
# Временные объекты
from tempfile import TemporaryDirectory
with TemporaryDirectory() as tmpdir:
# Работаем с временной директорией
pass # __exit__ удалит её
Ключевые моменты
- Гарантированный код очистки:
__exit__вызовется даже если произойдет исключение - Управление ресурсами: файлы, соединения, блокировки, память
- Простота: вместо try-finally пишется читаемый
withблок - Вложенность: можно использовать несколько контекстных менеджеров одновременно
Протокол контекстного менеджера — это фундаментальная часть Python для правильного управления ресурсами.