Ответ 1
Просто используйте raise;
(т.е. не создавайте ничего конкретного, просто raise;
) в блоке catch
, чтобы повторно поднять исключение без "сброса" трассировки.
У меня есть функция python, которая может вызвать исключение. Вызывающий получает исключение и имеет дело с ним. Теперь я хотел бы добавить декоратор к этой функции, которая также ловит исключение, выполняет некоторую обработку, но затем повторно вызывает исключение, чтобы позволить первому вызывающему пользователю обработать его. Это работает, за исключением того, что, когда исходный вызывающий абонент отображает стек вызовов из исключения, он показывает строку в декораторе, где он был повторно поднят, а не там, где он первоначально произошел. Пример кода:
import sys,traceback
def mydec(func):
def dec():
try:
func()
except Exception,e:
print 'Decorator handled exception %s' % e
raise e
return dec
@mydec
def myfunc():
x = 1/0
try:
myfunc()
except Exception,e:
print 'Exception: %s' % e
type,value,tb = sys.exc_info()
traceback.print_tb(tb)
Вывод:
Decorator handled exception integer division or modulo by zero
Exception: integer division or modulo by zero
File "allbug.py", line 20, in <module>
myfunc()
File "allbug.py", line 9, in dec
raise e
Я хотел бы, чтобы декоратор мог обрабатывать исключение, но трассировка должна указывать на строку x = 1/0
, а не на строку raise
. Как я могу это сделать?
Просто используйте raise;
(т.е. не создавайте ничего конкретного, просто raise;
) в блоке catch
, чтобы повторно поднять исключение без "сброса" трассировки.
Я просто написал класс, похожий на то, что вы делаете, но с немного больше доступных опций. Вот он:
class ErrorIgnore(object):
def __init__(self, errors, errorreturn = None, errorcall = None):
self.errors = errors
self.errorreturn = errorreturn
self.errorcall = errorcall
def __call__(self, function):
def returnfunction(*args, **kwargs):
try:
return function(*args, **kwargs)
except Exception as E:
if type(E) not in self.errors:
raise E
if self.errorcall is not None:
self.errorcall(E, *args, **kwargs)
return self.errorreturn
return returnfunction
Общее использование будет выглядеть примерно так:
def errorcall(E, *args):
print 'exception skipped', E
@ErrorIgnore(errors = [ZeroDivisionError, ValueError], errorreturn = None, errorcall = errorcall)
def myfunction(stuff):
# do stuff
# return stuff
# the errors shown are skipped