这个漂亮的小Python装饰器可以配置禁用装饰功能:
enabled = get_bool_from_config()
def run_if_enabled(fn):
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs) if enabled else None
except Exception:
log.exception('')
return None
return wrapped
唉,如果在fn()
内引发异常,则追溯仅显示包装器:
Traceback (most recent call last):
File "C:\my_proj\run.py", line 46, in wrapped
return fn(*args, **kwargs) if enabled else None
File "C:\my_proj\run.py", line 490, in a_decorated_function
some_dict['some_value']
KeyError: 'some_value'
答案 0 :(得分:6)
啊!好的,现在这是一个有趣的问题!
这是相同的近似函数,但直接从sys.exc_info()
:
import sys
import traceback
def save_if_allowed(fn):
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs) if enabled else None
except Exception:
print "The exception:"
print "".join(traceback.format_exception(*sys.exc_info()))
return None
return wrapped
@save_if_allowed
def stuff():
raise Exception("stuff")
def foo():
stuff()
foo()
确实如此:打印的回溯中不包含更高的堆栈帧:
$ python test.py The exception: Traceback (most recent call last): File "x.py", line 21, in wrapped return fn(*args, **kwargs) if enabled else None File "x.py", line 29, in stuff raise Exception("stuff") Exception: stuff
现在,为了缩小这一点,我怀疑它正在发生,因为堆栈帧只包含堆栈信息,直到最近的try/except
块...所以我们应该能够在没有装饰器的情况下重新创建它:
$ cat test.py
def inner():
raise Exception("inner")
def outer():
try:
inner()
except Exception:
print "".join(traceback.format_exception(*sys.exc_info()))
def caller():
outer()
caller()
$ python test.py
Traceback (most recent call last):
File "x.py", line 42, in outer
inner()
File "x.py", line 38, in inner
raise Exception("inner")
Exception: inner
啊哈哈!现在,经过反思,这确实以某种方式有意义:此时,异常只遇到两个堆栈帧:inner()
和{{1}的堆栈帧 - 异常尚未知道outer()
从哪里被调用。
因此,要获得完整的堆栈,您需要将当前堆栈与异常堆栈结合起来:
outer()
另见: