如何在装饰器中捕获异常并让调用者也能捕获?
我有一个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
这一行。我该怎么做呢?
2 个回答
8
我刚写了一个类,跟你做的差不多,不过提供了更多的选项。下面是我的代码:
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
19
在一个 catch
块里,只需要使用 raise;
(也就是说,不需要指定任何具体的错误,只用 raise;
)就可以重新抛出异常,而不会“重置”错误的追踪信息。