Работа с контекстными менеджерами: with, __enter__, __exit__

🔥 Контекстные менеджеры: магия автоматического управления ресурсами

Контекстные менеджеры в Python — это как надежный ассистент, который сам открывает и закрывает двери за вами. Они гарантируют, что ресурсы (файлы, соединения, транзакции) будут корректно освобождены, даже если что-то пойдет не так.

Вот классический пример работы с файлами без контекстного менеджера:

file = open("data.txt", "r")  # Открыли файл
try:
    content = file.read()     # Работаем с файлом
finally:
    file.close()              # Закрыли вручную (а если забудем?)

Теперь с контекстным менеджером:

with open("data.txt", "r") as file:  # Автоматическое закрытие!
    content = file.read()

Гораздо чище, правда?


🛠️ Как это работает: __enter__ и __exit__

Под капотом контекстные менеджеры используют два магических метода:
1. __enter__ — выполняется при входе в блок with (например, открытие файла).
2. __exit__ — выполняется при выходе (даже при ошибке!), освобождает ресурсы.

🔍 Создаем свой контекстный менеджер

Хотите управлять временем выполнения кода? Давайте сделаем таймер:

import time

class Timer:
    def __enter__(self):
        self.start_time = time.time()
        return self  # Возвращаем объект для использования в `with ... as`

    def __exit__(self, exc_type, exc_val, exc_tb):
        elapsed = time.time() - self.start_time
        print(f"Время выполнения: {elapsed:.2f} сек.")

# Используем:
with Timer():
    time.sleep(1.5)  # Имитация долгой операции

Вывод:

Время выполнения: 1.50 сек.

💡 Важно:
- __exit__ получает информацию об ошибке (если она возникла), но не паникует — ресурсы все равно будут освобождены!
- Если __exit__ возвращает True, исключение подавляется (используйте осторожно).


🎩 Альтернатива: contextlib

Не хотите писать класс? Модуль contextlib предлагает декоратор @contextmanager для создания контекстных менеджеров через генераторы:

from contextlib import contextmanager

@contextmanager
def rainbow_text(text):
    print(f"🌈 {text} 🌈")  # Аналог __enter__
    yield                   # Код внутри with выполняется здесь
    print("Все цвета сошлись!")  # Аналог __exit__

with rainbow_text("Python — это магия!"):
    print("Здесь может быть ваш код.")

Вывод:

🌈 Python — это магия! 🌈  
Здесь может быть ваш код.  
Все цвета сошлись!  

💼 Практические кейсы

1️⃣ Работа с БД (автозакрытие соединения)

import sqlite3
from contextlib import closing

with closing(sqlite3.connect("test.db")) as conn:
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users")
    print(cursor.fetchall())  # Соединение закроется само!

2️⃣ Временное изменение настроек

import matplotlib.pyplot as plt

with plt.style.context("dark_background"):  # Временно меняем стиль графиков
    plt.plot([1, 2, 3], [4, 5, 1])
    plt.show()  # После выхода стиль вернется к исходному

🚀 Вывод: когда и зачем использовать?

Контекстные менеджеры идеальны для:
- Работы с файлами, сетевыми соединениями, БД.
- Управления временными состояниями (настройки, блокировки).
- Автоматического освобождения ресурсов при ошибках.

👉 Совет от Данилы Бежина:
Если вы еще не используете with для работы с файлами — начинайте сегодня! Это избавит вас от тонн скрытых багов. Больше примеров — в его видео про контекстные менеджеры.

Теперь ваши Python-скрипты станут надежнее и чище. Вперед, к новым свершениям! 🐍✨

Скрыть рекламу навсегда

🧠 Учёба без воды и зубрёжки

Закрытый Boosty с наработками опытного преподавателя.

Объясняю сложное так, чтобы щелкнуло.

🚀 Забрать доступ к Boosty