0Pricing
Python Academy · Урок

Протокол __enter__ и __exit__

Создавайте менеджеры контекста с помощью специального протокола.

«Протокол __enter__ и __exit__» — бесплатный урок Python Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.

Протокол менеджера контекста

Любой объект, определяющий __enter__ и __exit__, является менеджером контекста и может использоваться с with.

class Managed:
    def __enter__(self):
        print("entering")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exiting")
        return False

with Managed() as m:
    print("inside")

Возвращаемое значение __enter__

__enter__ вызывается в начале блока with. Его возвращаемое значение присваивается переменной после as.

class Resource:
    def __enter__(self):
        self.value = 42
        return self  # bound to 'r'

    def __exit__(self, *args):
        self.value = None
        return False

with Resource() as r:
    print(r.value)  # 42

Аргументы __exit__

__exit__(exc_type, exc_val, exc_tb) получает сведения об исключении, если произошла ошибка. Если исключения нет, все три значения равны None.

class Safe:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is ValueError:
            print(f"Suppressed ValueError: {exc_val}")
            return True   # suppress the exception
        return False      # re-raise anything else

with Safe():
    raise ValueError("oops")  # suppressed

Подавление исключений

Верните True из __exit__, чтобы подавить исключение. Верните False или ничего не возвращайте, чтобы передать его дальше.

class Ignore:
    def __enter__(self): return self
    def __exit__(self, *args): return True  # swallow all exceptions

with Ignore():
    1 / 0

print("continues here")

Пример подключения к базе данных

Классический вариант использования: получить подключение при входе, зафиксировать изменения или выполнить откат, а затем закрыть подключение при выходе.

class DBConn:
    def __enter__(self):
        self.conn = connect_db()
        return self.conn

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            self.conn.rollback()
        else:
            self.conn.commit()
        self.conn.close()
        return False

Менеджер контекста Timer

Измеряйте прошедшее время: сохраните момент начала в __enter__, а в __exit__ вычислите разницу.

import time

class Timer:
    def __enter__(self):
        self.start = time.perf_counter()
        return self

    def __exit__(self, *args):
        self.elapsed = time.perf_counter() - self.start
        print(f"Elapsed: {self.elapsed:.3f}s")
        return False

with Timer():
    sum(range(1_000_000))

Вложенные менеджеры контекста

Несколько менеджеров контекста можно объединить в одной строке with.

with open("in.txt") as src, open("out.txt", "w") as dst:
    dst.write(src.read())

Повторно используемые и одноразовые менеджеры

Менеджеры контекста, у которых __enter__ каждый раз выделяет новый ресурс, можно использовать повторно. Менеджеры, исчерпывающие внутреннее состояние (например, блокировка, удерживаемая только один раз), могут быть непригодны для повторного использования.

class Reusable:
    def __enter__(self):
        return []
    def __exit__(self, *a):
        return False

for _ in range(3):
    with Reusable() as lst:
        lst.append(1)
        print(lst)  # [1] each time

__aenter__ и __aexit__ (асинхронный режим)

Для асинхронных менеджеров контекста определите корутины __aenter__ и __aexit__ и используйте async with.

class AsyncDB:
    async def __aenter__(self):
        self.conn = await connect()
        return self.conn

    async def __aexit__(self, *args):
        await self.conn.close()

# async with AsyncDB() as conn:
#     ...

Обёртка файловых объектов

Файловые объекты Python уже реализуют протокол менеджера контекста — никогда не вызывайте f.close() вручную.

with open("data.txt", "r") as f:
    data = f.read()
# file is closed here automatically
print(f.closed)  # True

Реализация блокировки

Блокировки потоков являются менеджерами контекста: __enter__ захватывает блокировку, а __exit__ освобождает её.

import threading

lock = threading.Lock()

def update_shared():
    with lock:
        # critical section
        pass

Быстрая проверка

Что должен возвращать __exit__, чтобы подавить исключение?

Итоги

Реализуйте __enter__ и __exit__, чтобы создавать менеджеры контекста. Возвращайте ресурс из __enter__, а в __exit__ обрабатывайте очистку и подавление исключений.

Часто задаваемые вопросы

Урок «Протокол __enter__ и __exit__» бесплатный?

Да — полный текст урока «Протокол __enter__ и __exit__» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.

Чему я научусь в уроке «Протокол __enter__ и __exit__»?

Создавайте менеджеры контекста с помощью специального протокола. Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Python Academy?

Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Протокол __enter__ и __exit__»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Python Academy?

Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Оператор with подробно
  2. Протокол __enter__ и __exit__
  3. contextlib: @contextmanager
  4. Практические шаблоны менеджеров контекста
← Назад к Python Academy