← Назад к вопросам

Как работает контекстный менеджер в 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

Порядок выполнения:

  1. Вычисляется expression, получается объект менеджера
  2. Вызывается __enter__(), результат присваивается variable
  3. Выполняется блок кода
  4. Вызывается __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 для безопасной и элегантной работы с ресурсами.

Как работает контекстный менеджер в Python? | PrepBro