编辑:以前的版本没有提供引用或解释。
我建议参考PEP 3134 动机中的说明:
有时,故意让异常处理程序很有用
重新引发异常,以提供额外信息或
将异常转换为另一种类型。 __cause__ 属性
提供了一种明确的方式来记录异常的直接原因。
当使用__cause__ 属性引发Exception 时,回溯消息采用以下形式:
Traceback (most recent call last):
<CAUSE TRACEBACK>
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
<MAIN TRACEBACK>
据我了解,这正是您想要完成的;清楚地表明错误的原因不是您的模块,而是其他地方。如果您想像 edit 建议的那样尝试省略回溯的信息,那么这个答案的其余部分对您没有任何好处。
只是语法说明:
异常对象的__cause__ 属性总是被初始化
为无。它由一种新形式的“raise”语句设置:
raise EXCEPTION from CAUSE
相当于:
exc = EXCEPTION
exc.__cause__ = CAUSE
raise exc
所以最起码的例子应该是这样的:
def function():
int("fail")
def check_raise(function):
try:
function()
except Exception as original_error:
err = RuntimeError("An exception was raised.")
raise err from original_error
check_raise(function)
它会给出如下错误消息:
Traceback (most recent call last):
File "/PATH/test.py", line 7, in check_raise
function()
File "/PATH/test.py", line 3, in function
int("fail")
ValueError: invalid literal for int() with base 10: 'fail'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/PATH/test.py", line 12, in <module>
check_raise(function)
File "/PATH/test.py", line 10, in check_raise
raise err from original_error
RuntimeError: An exception was raised.
然而第一行的原因是check_raise的try块中的语句:
File "/PATH/test.py", line 7, in check_raise
function()
所以在提升err 之前,可能(或可能不)需要从original_error 中删除最外层的回溯帧:
except Exception as original_error:
err = RuntimeError("An exception was raised.")
original_error.__traceback__ = original_error.__traceback__.tb_next
raise err from original_error
这样,回溯中唯一似乎来自check_raise 的行是最后一个raise 语句,纯python代码不能省略该语句,尽管取决于消息的信息量,您可以非常清楚地说明您的模块不是问题的原因:
err = RuntimeError("""{0.__qualname__} encountered an error during call to {1.__module__}.{1.__name__}
the traceback for the error is shown above.""".format(function,check_raise))
像这样引发异常的好处是在引发新的错误时不会丢失原始的 Traceback 消息,这意味着可以引发一系列非常复杂的异常,python 仍然会正确显示所有相关信息:
def check_raise(function):
try:
function()
except Exception as original_error:
err = RuntimeError("""{0.__qualname__} encountered an error during call to {1.__module__}.{1.__name__}
the traceback for the error is shown above.""".format(function,check_raise))
original_error.__traceback__ = original_error.__traceback__.tb_next
raise err from original_error
def test_chain():
check_raise(test)
def test():
raise ValueError
check_raise(test_chain)
给我以下错误信息:
Traceback (most recent call last):
File "/Users/Tadhg/Documents/test.py", line 16, in test
raise ValueError
ValueError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/Tadhg/Documents/test.py", line 13, in test_chain
check_raise(test)
File "/Users/Tadhg/Documents/test.py", line 10, in check_raise
raise err from original_error
RuntimeError: test encountered an error during call to __main__.check_raise
the traceback for the error is shown above.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/Tadhg/Documents/test.py", line 18, in <module>
check_raise(test_chain)
File "/Users/Tadhg/Documents/test.py", line 10, in check_raise
raise err from original_error
RuntimeError: test_chain encountered an error during call to __main__.check_raise
the traceback for the error is shown above.
是的,它很长,但它显着提供更多信息:
Traceback (most recent call last):
File "/Users/Tadhg/Documents/test.py", line 18, in <module>
check_raise(test_chain)
RuntimeError: An exception was raised.
更不用说即使程序没有结束,原来的错误仍然可以使用:
import traceback
def check_raise(function):
...
def fail():
raise ValueError
try:
check_raise(fail)
except RuntimeError as e:
cause = e.__cause__
print("check_raise failed because of this error:")
traceback.print_exception(type(cause), cause, cause.__traceback__)
print("and the program continues...")