异常回溯在未立即重新抛出时被隐藏
我有一段代码,差不多是这样的:
import sys
def func1():
func2()
def func2():
raise Exception('test error')
def main():
err = None
try:
func1()
except:
err = sys.exc_info()[1]
pass
# some extra processing, involving checking err details (if err is not None)
# need to re-raise err so caller can do its own handling
if err:
raise err
if __name__ == '__main__':
main()
当 func2
抛出一个异常时,我收到了以下的错误追踪信息:
Traceback (most recent call last):
File "err_test.py", line 25, in <module>
main()
File "err_test.py", line 22, in main
raise err
Exception: test error
从这里我看不出这个异常是从哪里来的。原始的错误追踪信息丢失了。
我该如何保留原始的错误追踪信息并重新抛出它呢?我想看到类似这样的内容:
Traceback (most recent call last):
File "err_test.py", line 26, in <module>
main()
File "err_test.py", line 13, in main
func1()
File "err_test.py", line 4, in func1
func2()
File "err_test.py", line 7, in func2
raise Exception('test error')
Exception: test error
7 个回答
8
你可以通过 sys.exc_info()
这个方法,配合 traceback 模块,获取很多关于错误的信息。
试试在你的代码中加上下面这个扩展。
import sys
import traceback
def func1():
func2()
def func2():
raise Exception('test error')
def main():
try:
func1()
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
# Do your verification using exc_value and exc_traceback
print "*** print_exception:"
traceback.print_exception(exc_type, exc_value, exc_traceback,
limit=3, file=sys.stdout)
if __name__ == '__main__':
main()
这样就会打印出你想要的类似内容。
*** print_exception:
Traceback (most recent call last):
File "err_test.py", line 14, in main
func1()
File "err_test.py", line 5, in func1
func2()
File "err_test.py", line 8, in func2
raise Exception('test error')
Exception: test error
72
可以对异常进行修改并重新抛出:
如果没有提供任何表达式,
raise
会重新抛出当前作用域内最后一个活跃的异常。如果当前作用域没有活跃的异常,就会抛出一个TypeError
异常,表示这是一个错误(如果在 IDLE 环境下运行,则会抛出Queue.Empty
异常)。如果有其他表达式,
raise
会计算这些表达式,得到三个对象,省略的表达式会用None
作为值。前两个对象用来确定异常的类型和具体值。如果第三个对象存在且不为
None
,它必须是一个追踪对象(可以参考标准类型层次结构),并且会替代当前的位置,作为异常发生的地方。如果第三个对象存在但不是追踪对象或None
,则会抛出一个TypeError
异常。使用三表达式形式的
raise
在except
语句中透明地重新抛出异常是很有用的,但如果要重新抛出的异常是当前作用域内最近活跃的异常,建议使用不带表达式的raise
。
所以,如果你想修改异常并重新抛出,可以这样做:
try:
buggy_code_which_throws_exception()
except Exception as e:
raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2]
129
一个空的 raise
会重新抛出最后一个异常。
# need to re-raise err so caller can do its own handling
if err:
raise
如果你使用 raise something
,Python 无法判断 something
是之前捕获到的异常,还是一个新的异常并且有新的调用记录。这就是为什么会有空的 raise
,它可以保留调用记录。