Joe*_*oel 9 python python-3.x python-3.5
在模块警告(https://docs.python.org/3.5/library/warnings.html)中,可以发出似乎来自堆栈中某个位置的警告:
warnings.warn('This is a test', stacklevel=2)
Run Code Online (Sandbox Code Playgroud)
是否存在引发错误的等价物?我知道我可以使用备用回溯引发错误,但我无法在模块中创建该回溯,因为它需要来自之前的版本.我想象的是:
tb = magic_create_traceback_right_here()
raise ValueError('This is a test').with_traceback(tb.tb_next)
Run Code Online (Sandbox Code Playgroud)
原因是我正在开发一个具有一个函数的模块,module.check_raise我想引发一个看起来源于函数调用位置的错误.如果我在module.check_raise函数内引发错误,它似乎来自内部module.check_raise,这是不希望的.
此外,我尝试了一些技巧,比如提出一个虚拟异常,捕获它,然后传递回溯,但不知怎的,tb_next变成了None.我没有想法.
编辑:
我想要这个最小例子的输出(称为tb2.py):
import check_raise
check_raise.raise_if_string_is_true('True')
Run Code Online (Sandbox Code Playgroud)
只有这个:
Traceback (most recent call last):
File "tb2.py", line 10, in <module>
check_raise.raise_if_string_is_true(string)
RuntimeError: An exception was raised.
Run Code Online (Sandbox Code Playgroud)
编辑:以前的版本没有提供引用或解释。
我建议参考PEP 3134,其中在动机中指出:
有时,异常处理程序有意重新引发异常可能很有用,可以提供额外的信息,也可以将异常转换为另一种类型。该
__cause__属性提供了一种显式的方式来记录异常的直接原因。
当Exception使用属性引发时__cause__,回溯消息采用以下形式:
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>
Run Code Online (Sandbox Code Playgroud)
据我了解,这正是您想要实现的目标;清楚地表明错误的原因不是您的模块而是其他地方。如果您尝试像编辑建议的那样省略回溯信息,那么这个答案的其余部分不会对您有任何好处。
只是语法上的注释:
异常对象的属性
__cause__始终初始化为 None。它由新形式的“raise”语句设置:Run Code Online (Sandbox Code Playgroud)raise EXCEPTION from CAUSE这相当于:
Run Code Online (Sandbox Code Playgroud)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)
Run Code Online (Sandbox Code Playgroud)
它给出了这样的错误消息:
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.
Run Code Online (Sandbox Code Playgroud)
try然而,原因的第一行是块中的语句check_raise:
File "/PATH/test.py", line 7, in check_raise
function()
Run Code Online (Sandbox Code Playgroud)
因此,在提出之前,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
Run Code Online (Sandbox Code Playgroud)
这样,回溯中唯一出现的行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))
Run Code Online (Sandbox Code Playgroud)
像这样引发异常的优点是,当引发新错误时,原始 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)
Run Code Online (Sandbox Code Playgroud)
给我以下错误消息:
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.
Run Code Online (Sandbox Code Playgroud)
是的,它很长,但它的信息量要大得多:
Traceback (most recent call last):
File "/Users/Tadhg/Documents/test.py", line 18, in <module>
check_raise(test_chain)
RuntimeError: An exception was raised.
Run Code Online (Sandbox Code Playgroud)
更不用说即使程序没有结束,原始错误仍然可用:
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...")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2518 次 |
| 最近记录: |