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

Создание своего менеджера контекста

Содержание курса

FAQ

Задавайте вопросы в комментариях — мы будем расширять раздел.

  1. Зачем __enter__ возвращает self (или другой объект)?
    Возвращённое значение привязывается к имени после as ... в конструкции with. Если нужен доступ к данным менеджера внутри блока, обычно возвращают self (with Timer() as t:). Если ничего не нужно — можно вернуть None.
  2. Что будет, если в __exit__ вернуть True?
    Исключение, возникшее в блоке with, будет подавлено и не «уйдёт» выше по стеку. Возврат False (или None) оставляет исключение активным.
  3. Можно ли использовать print в __exit__ вместо логирования?
    Технически можно, но для реального кода лучше применить logging — так сообщения можно фильтровать и перенаправлять.
  4. Что произойдёт, если в __exit__ само возникнет новое исключение?
    Наружу выйдет новое исключение, а исходное обычно останется в его __context__ и будет видно в цепочке traceback. contextlib.ExitStack сам по себе не подавляет ошибки очистки. Политику обработки таких ошибок нужно задать явно.
  5. Нужно ли явно вызывать Timer.__exit__ вне with?
    После успешного __enter__ конструкция with вызовет __exit__ автоматически. Ручной вызов допустим (например, при тестировании), но редко нужен.
  6. Как сделать менеджер, который только подавляет исключения определённого типа?
    Проверяйте exc_type и возвращайте True только для нужных исключений:
    
    def __exit__(self, exc_type, exc_val, tb):
        return exc_type is FileNotFoundError
        
  7. Можно ли написать менеджер без класса?
    Да, с помощью @contextlib.contextmanager:
    
    import time
    from contextlib import contextmanager
    @contextmanager
    def timer():
            start = time.perf_counter()
            try:
                yield
            finally:
                print(time.perf_counter() - start)
        
    Код до yield выполняется при входе. Исключение из блока возобновляет генератор в точке yield; очистка в finally выполняется и при таком выходе.
  8. Будет ли ChangeDir безопасен при вложенных вызовах?
    Если одновременно используется несколько экземпляров («матрёшка»), каждый запоминает свою old_path, поэтому восстановление происходит корректно в последовательном коде, если исходные директории доступны. Повторный вложенный вход в тот же экземпляр перезапишет old_path. Изменение рабочей директории действует на весь процесс, поэтому параллельное использование небезопасно.

Начать заново?

Помощник начнёт новый диалог по этой задаче. Текущая переписка останется в истории до конца срока хранения.

О переписке

Можно приложить до трёх фото PNG, JPEG или WebP по 5 МБ.

Переписка и фото хранятся 90 дней после последнего принятого сообщения. Преподаватель получит доступ к диалогу, когда вы попросите его помочь.

Проверка решения остаётся отдельным действием.