Menu
Coddy logo textTech

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

Часть раздела Object Oriented Programming путешествия по Python на Coddy — урок 41 из 64.

Менеджеры контекста позволяют выделять и освобождать ресурсы именно тогда, когда это необходимо. Они обеспечивают правильную очистку даже в случае возникновения ошибок.

Вот самый распространенный пример использования инструкции with:

with open('example.txt', 'w') as file:
    file.write('Hello, world!')
# Файл автоматически закрывается здесь

Файл автоматически закрывается после завершения блока, даже если возникает исключение.

Создайте свой собственный менеджер контекста, реализовав методы __enter__ и __exit__:

class MyContext:
    def __enter__(self):
        print("Entering the context")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting the context")
        return False  # Не подавлять исключения

Используйте свой собственный менеджер контекста:

with MyContext() as ctx:
    print("Inside the context")

Вывод:

Entering the context
Inside the context
Exiting the context

Создайте более практичный менеджер контекста для подключений к базе данных:

class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
        self.connection = None
    
    def __enter__(self):
        print(f"Connecting to {self.db_name}")
        self.connection = f"Connection to {self.db_name}"
        return self.connection
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"Closing connection to {self.db_name}")
        self.connection = None

with DatabaseConnection("users_db") as conn:
    print(f"Using {conn}")
    print("Performing database operations...")

Обработка исключений в контекстных менеджерах:

class SafeContext:
    def __enter__(self):
        print("Setting up resources")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up resources")
        if exc_type:
            print(f"An exception occurred: {exc_val}")
        return False  # Не подавлять исключение

with SafeContext():
    print("Working with resources")
    # raise ValueError("Something went wrong")  # Раскомментируйте для тестирования

Вывод:

Connecting to users_db
Using Connection to users_db
Performing database operations...
Closing connection to users_db
Setting up resources
Working with resources
Cleaning up resources

Метод __exit__ принимает три параметра:

  • exc_type: Тип исключения (или None)
  • exc_val: Значение исключения (или None)
  • exc_tb: Трассировка исключения (или None)

Ключевой момент: Менеджеры контекста используют методы __enter__ и __exit__ для управления ресурсами. Инструкция with автоматически вызывает эти методы, обеспечивая правильную настройку и очистку. Это особенно полезно для файлов, подключений к базам данных и других ресурсов, требующих гарантированной очистки.

challenge icon

Задание

Легко

В этом испытании вам предстоит реализовать класс менеджера контекста, который измеряет время, прошедшее между входом в блок контекста и выходом из него.

  • timer.py — содержит реализацию класса Timer (это файл, который вы будете редактировать)
  • driver.py — содержит комплексные тестовые случаи (не изменять)

Реализуйте менеджер контекста Timer в timer.py, следуя комментариям TODO. Класс должен:

  1. Записывать время начала при входе в контекст
  2. Записывать время окончания при выходе
  3. Вычислять и отображать прошедшее время

Шпаргалка

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

Используйте оператор with для автоматического управления ресурсами:

with open('example.txt', 'w') as file:
    file.write('Hello, world!')
# Файл автоматически закрывается здесь

Создавайте пользовательские менеджеры контекста, реализуя методы __enter__ и __exit__:

class MyContext:
    def __enter__(self):
        print("Entering the context")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting the context")
        return False  # Не подавлять исключения

with MyContext() as ctx:
    print("Inside the context")

Метод __exit__ принимает три параметра:

  • exc_type: Тип исключения (или None)
  • exc_val: Значение исключения (или None)
  • exc_tb: Трассировка исключения (или None)

Обработка исключений в менеджерах контекста:

class SafeContext:
    def __enter__(self):
        print("Setting up resources")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up resources")
        if exc_type:
            print(f"An exception occurred: {exc_val}")
        return False  # Не подавлять исключение

Попробуйте сами

from timer import Timer
import time

# Обработчик тестовых случаев
test_case = input()

if test_case == "basic_test":
    # Тест базовой функциональности
    with Timer():
        # Симуляция работы
        time.sleep(2)  # Это заставляет программу ждать 2 секунды

elif test_case == "nested_contexts":
    # Тест вложенных контекстных менеджеров
    with Timer():
        time.sleep(1)
        with Timer():
            time.sleep(1)

elif test_case == "exception_handling":
    # Тест обработки исключений внутри контекста
    try:
        with Timer():
            time.sleep(1)
            raise ValueError("Test exception")
    except ValueError as e:
        print(f"Caught exception: {e}")

elif test_case == "zero_sleep":
    # Тест с минимальной задержкой
    with Timer():
        time.sleep(0.001)

elif test_case == "multiple_timers":
    # Тест нескольких таймеров последовательно
    with Timer():
        time.sleep(1)
    
    with Timer():
        time.sleep(0.5)
    
    with Timer():
        time.sleep(2)

elif test_case == "as_decorator":
    # Тест таймера в контексте функции
    def timed_function():
        with Timer():
            time.sleep(2)
    
    timed_function()

else:
    # Тест по умолчанию - базовая функциональность
    with Timer():
        # Симуляция работы
        time.sleep(2)  # Это заставляет программу ждать 2 секунды
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming