#python #python-2.7 #exception-handling #with-statement #contextmanager
#python #python-2.7 #исключение #with-statement #contextmanager
Вопрос:
Рассмотрим следующий фрагмент кода:
class Test(object):
def __enter__(self):
pass
def __exit__(self,type,value,trace):
if type:
print "Error occured: " str(value.args)
#if I changed the next line to 'return True', the
#'print "should not happen"' statements are executed, but the
#error information would be only printed once (what I want)
return False
return True
with Test():
with Test():
with Test():
raise Exception('Foo','Bar')
print "should not happen"
print "should not happen"
Вывод примера:
Произошла ошибка: (‘Foo’, ‘Bar’)
Произошла ошибка: (‘Foo’, ‘Bar’)
Произошла ошибка: (‘Foo’, ‘Bar’)
У меня есть несколько вложенных with
операторов, и я хочу обработать случай, когда исключение возникает где-то в коде. Чего я хочу добиться, так это того, чтобы выполнение было остановлено (в приведенном выше примере вывода «не должно произойти» нет), но информация об ошибке выводится только один раз. Поэтому мне нужно каким-то образом узнать, была ли уже обработана та же ошибка.
У вас есть какие-либо идеи, как этого можно достичь?
Комментарии:
Ответ №1:
На самом деле вы не можете сделать это чисто — либо диспетчер контекста проглатывает исключение, либо нет.
Если у вас все в порядке с исключением, распространяющимся из диспетчера (что должно быть так, если вы обрабатываете здесь произвольные исключения), вы можете вручную исправить экземпляр исключения:
def __exit__(self, type, value, trace):
if type:
if not getattr(value, '_printed_it_already', False):
print "error occured: " str(value.args)
value._printed_it_already = True
return False
return True
Обратите внимание, что такого рода исправление ошибок в Python не одобряется … Я думаю, стоит спросить, что вы на самом деле пытаетесь сделать. Обычно, когда необработанное исключение выводит свою трассировку стека, вы получаете довольно хорошее представление о том, с чего args
должно было начинаться исключение…
Комментарии:
1. именно то, что я искал, спасибо! Я знаю, что это не очень хорошая практика. Я создал небольшой task runner, где каждый
with
представляет некоторый вид транзакции.with
Синтаксис прост в использовании для этого, но моей единственной проблемой было вывести ошибку (и сделать это только один раз)
Ответ №2:
Вы можете добавить error_handled
атрибут к исключению и протестировать его:
class Test(object):
def __enter__(self):
pass
def __exit__(self,type,value,trace):
if type:
if not getattr(value,'error_handled', False):
value.error_handled = True
print "Error occured: " str(value.args)
with Test():
with Test():
with Test():
raise Exception('Foo','Bar')
print "should not happen"
print "should not happen"