Правильный способ обработки исключений в классе менеджера контекста Python2.7

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

У меня сложилось впечатление, что вы не должны повторно вызывать исключения, переданные в качестве аргументов методу __exit__ класса диспетчера контекста. Тем не менее, я проводил некоторое тестирование, и мне показалось, что диспетчер контекста подавлял исключение, которое возникало внутри него. Когда я изменил свои методы __exit__, чтобы они выглядели так:

def __exit__(self, type_, value, trace):
    if trace is not None:
        print('ERROR IN TRACEBACK: ' + str(value))
        # PYTHON 2.7 RAISE SYNTAX:
        raise type_, value, trace

ошибки, казалось, прошли правильно.

Мой вопрос: как правильно обрабатывать исключения в методе __exit__, если type_, value и trace не равны None? Плохо ли поднимать (повторно поднимать?) такое исключение? Это то, как я должен это сделать?

Ошибка, с которой я столкнулся, могла быть вызвана чем-то другим. Обычно я бы прошел и проверил все это тщательно, но мое время, кажется, очень ограничено в данный момент. Я надеюсь, что кто-нибудь сможет объяснить правильную реализацию этой функции и

В конечном счете: могу ли я безопасно оставить повышение типа_, значения, трассировки в моих методах __exit__ контекстного менеджера?


person Erotemic    schedule 10.07.2014    source источник


Ответы (1)


Возвращаемое значение метода __exit__ должно указывать, следует ли повторно вызвать переданное ему исключение (согласно документы):

contextmanager.__exit__(exc_type, exc_val, exc_tb)

Выйдите из контекста среды выполнения и верните логический флаг, указывающий, следует ли подавлять какое-либо возникшее исключение. Если при выполнении тела оператора with возникло исключение, аргументы содержат тип исключения, значение и информацию о трассировке. В противном случае все три аргумента равны None.

Итак, пока ваш метод __exit__ возвращает что-то False-y, исключение должно быть повторно вызвано без каких-либо явных действий.

Кроме того, в документации указано, что не повторно вызывать исключение самостоятельно:

Переданное исключение никогда не должно вызываться повторно явно — вместо этого этот метод должен возвращать ложное значение, указывающее, что метод завершился успешно и не хочет подавлять возбужденное исключение. Это позволяет коду управления контекстом (такому как contextlib.nested) легко определить, действительно ли метод __exit__() дал сбой.

person dano    schedule 10.07.2014
comment
Я думал, что None — это значение False-y... И теперь, когда я смотрю на код, я понимаю, что возвращаю что-то сам объект. (Что, если не изменяет память, должно возвращаться методом _enter_). - person Erotemic; 11.07.2014