啊! 好的,现在这是一个有趣的问题!
这是相同的近似函数,但直接从以下位置获取异常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()
确实如此:打印的回溯中不包含更高的堆栈帧:
$蟒蛇测试.py
例外:
回溯(最近一次通话最后):
文件“x.py”,第 21 行,已包装
如果启用则返回 fn(*args, **kwargs) 否则无
文件“x.py”,第 29 行,in 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
啊哈!现在,仔细想想,这在某种意义上确实是有意义的:此时,异常只遇到了两个堆栈帧:ofinner()
和 of outer()
——异常还不知道从哪里outer()
调用。
因此,要获得完整的堆栈,您需要将当前堆栈与异常堆栈结合起来:
$ cat test.py
def inner():
raise Exception("inner")
def outer():
try:
inner()
except Exception:
exc_info = sys.exc_info()
stack = traceback.extract_stack()
tb = traceback.extract_tb(exc_info[2])
full_tb = stack[:-1] + tb
exc_line = traceback.format_exception_only(*exc_info[:2])
print "Traceback (most recent call last):"
print "".join(traceback.format_list(full_tb)),
print "".join(exc_line)
def caller():
outer()
caller()
$ python test.py
Traceback (most recent call last):
File "test.py", line 56, in <module>
caller()
File "test.py", line 54, in caller
outer()
File "test.py", line 42, in outer
inner()
File "test.py", line 38, in inner
raise Exception("inner")
Exception: inner
也可以看看: