Как манипулировать исключением при выходе из context manager?
Я знаю, что это плохой стиль, чтобы повторно вызвать исключение из контекстного менеджера __exit__()
метод. Итак, я хотел бы прикрепить атрибут к экземпляру, который может нести контекстную информацию, которая недоступна, если я позволю исключению просочиться или если я его поймаю. Это позволит избежать его повторного поднятия.
альтернативой привязке атрибута к исключению было бы проглотить исключение, установить некоторое состояние на экземпляре, который удваивается как менеджер контекста в вопросе и позже проверьте это состояние. Проблема в том, что это приведет к Уловке 22, не так ли? Поскольку исключение означает, что выполнение внутри with
блок выходящего. Нет никакого способа повторить операцию, кроме как ввести with
блок снова, верно? Таким образом, экземпляр, в котором я пытаюсь сохранить контекстную информацию, исчезнет после __exit__()
возвращает метод.
короче говоря: как я могу манипулировать фактическим исключением, которое ожидает (если это так, что я предположу как дали на этот вопрос), а в __exit__()
способ?
1 ответов
менеджер контекста не уходит только потому, что блок выходит. Вы можете сохранить его двумя способами:
-
сначала создайте менеджер контекста, назначьте его переменной, затем используйте
with
С этим объектом:cm = ContextManager() with cm: # .... state = cm.attribute
-
верните сам менеджер контекста из
__enter__
способ использованияwith ... as ...
чтобы привязать это к локальному имени. Это имя не развязано, когдаwith
выходы:with ContextManager as cm: # .... state = cm.attribute
здесь
ContextManager.__enter__
используетreturn self
.
вы также можете установить дополнительные атрибуты самого исключения; нет необходимости повторно вызывать исключение:
>>> class ContextManager(object):
... def __enter__(self):
... return self
... def __exit__(self, tp, v, tb):
... if tp is None: return
... v.extra_attribute = 'foobar'
... self.other_extra_attribute = 'spam-n-ham'
...
>>> try:
... with ContextManager() as cm:
... raise ValueError('barfoo')
... except ValueError as ex:
... print vars(ex)
...
{'extra_attribute': 'foobar'}
>>> vars(cm)
{'other_extra_attribute': 'spam-n-ham'}
здесь исключению был предоставлен дополнительный атрибут, который сохранялся до самого обработчика исключений. В приведенном выше я также показываю, что cm
по-прежнему привязан к контексту менеджер.