Создание своего менеджера контекста
Содержание курса
FAQ
Задавайте вопросы в комментариях — мы будем расширять раздел.
-
Зачем
__enter__возвращаетself(или другой объект)?
Возвращённое значение привязывается к имени послеas ...в конструкцииwith. Если нужен доступ к данным менеджера внутри блока, обычно возвращаютself(with Timer() as t:). Если ничего не нужно — можно вернутьNone. -
Что будет, если в
__exit__вернутьTrue?
Исключение, возникшее в блокеwith, будет подавлено и не «уйдёт» выше по стеку. ВозвратFalse(илиNone) оставляет исключение активным. -
Можно ли использовать
printв__exit__вместо логирования?
Технически можно, но для реального кода лучше применитьlogging— так сообщения можно фильтровать и перенаправлять. -
Что произойдёт, если в
__exit__само возникнет новое исключение?
Наружу выйдет новое исключение, а исходное обычно останется в его__context__и будет видно в цепочке traceback.contextlib.ExitStackсам по себе не подавляет ошибки очистки. Политику обработки таких ошибок нужно задать явно. -
Нужно ли явно вызывать
Timer.__exit__внеwith?
После успешного__enter__конструкцияwithвызовет__exit__автоматически. Ручной вызов допустим (например, при тестировании), но редко нужен. -
Как сделать менеджер, который только подавляет исключения определённого типа?
Проверяйтеexc_typeи возвращайтеTrueтолько для нужных исключений:def __exit__(self, exc_type, exc_val, tb): return exc_type is FileNotFoundError -
Можно ли написать менеджер без класса?
Да, с помощью@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выполняется и при таком выходе. -
Будет ли
ChangeDirбезопасен при вложенных вызовах?
Если одновременно используется несколько экземпляров («матрёшка»), каждый запоминает своюold_path, поэтому восстановление происходит корректно в последовательном коде, если исходные директории доступны. Повторный вложенный вход в тот же экземпляр перезапишетold_path. Изменение рабочей директории действует на весь процесс, поэтому параллельное использование небезопасно.
