← Назад к вопросам
Как работает контекстный менеджер в Python?
2.2 Middle🔥 191 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Контекстные менеджеры в Python
Контекстный менеджер — это объект, который определяет, что происходит в блоке with. Он управляет ресурсами, обеспечивая их корректное получение и освобождение, даже если возникла ошибка.
Как работает контекстный менеджер
Контекстный менеджер основан на двух методах:
__enter__()— вызывается при входе в блокwith, возвращает ресурс__exit__()— вызывается при выходе из блокаwith, освобождает ресурс
with expression as variable:
# Блок кода
pass
Порядок выполнения:
- Вычисляется
expression, получается объект менеджера - Вызывается
__enter__(), результат присваиваетсяvariable - Выполняется блок кода
- Вызывается
__exit__()(всегда, даже если была ошибка)
Пример: простой контекстный менеджер
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)
print(f"Файл {self.filename} открыт")
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
if self.file:
self.file.close()
print(f"Файл {self.filename} закрыт")
# Если вернуть True, исключение будет подавлено
return False
with FileManager("test.txt", "w") as f:
f.write("Привет, мир!")
# Вывод: Файл test.txt открыт
# Вывод: Файл test.txt закрыт
Параметры __exit__()
Метод __exit__() получает три параметра:
exc_type— тип исключения (илиNone)exc_val— значение исключения (илиNone)exc_tb— traceback (илиNone)
Если в блоке произойдет ошибка, эти параметры будут содержать информацию об ошибке.
class ErrorHandler:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None:
print(f"Поймали ошибку: {exc_type.__name__}: {exc_val}")
return True # Подавляем исключение
return False
with ErrorHandler():
print("Начало работы")
x = 1 / 0 # ZeroDivisionError
print("Этот код не выполнится")
# Вывод: Начало работы
# Вывод: Поймали ошибку: ZeroDivisionError: division by zero
Декоратор @contextmanager
Для простых случаев можно использовать декоратор contextmanager из модуля contextlib:
from contextlib import contextmanager
@contextmanager
def database_connection(db_name):
# __enter__ часть
print(f"Подключение к БД {db_name}")
connection = f"Connection to {db_name}"
try:
yield connection
finally:
# __exit__ часть
print(f"Отключение от БД {db_name}")
with database_connection("users") as conn:
print(f"Работаю с: {conn}")
# Вывод: Подключение к БД users
# Вывод: Работаю с: Connection to users
# Вывод: Отключение от БД users
Практические примеры
Измерение времени выполнения
from contextlib import contextmanager
import time
@contextmanager
def timer(name):
start = time.time()
print(f"Начало: {name}")
try:
yield
finally:
elapsed = time.time() - start
print(f"Завершено {name} за {elapsed:.2f}с")
with timer("операция"):
time.sleep(1)
Управление транзакциями
@contextmanager
def transaction(connection):
try:
yield connection
connection.commit()
print("Транзакция успешна")
except Exception as e:
connection.rollback()
print(f"Откат транзакции: {e}")
raise
with transaction(db) as conn:
conn.execute("INSERT INTO users VALUES (...)")
Ключевые преимущества
- Гарантированное освобождение ресурсов — даже при ошибках
- Чистый и читаемый код — вместо try/finally
- Безопасность — автоматическое управление состоянием
- Переиспользуемость — легко применять к разным ресурсам
Контекстные менеджеры — это фундаментальный паттерн в Python для безопасной и элегантной работы с ресурсами.