Tob*_*ler 80 python nested exception raise
我知道如果我想重新引发一个异常,我raise在相应的except块中使用不带参数.但是给出了一个嵌套的表达式
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e # I'd like to raise the SomeError as if plan_B()
# didn't raise the AlsoFailsError
Run Code Online (Sandbox Code Playgroud)
如何在SomeError不破坏堆栈跟踪的情况下重新提升?raise在这种情况下,单独会重新提高最近AlsoFailsError.或者我怎么能重构我的代码以避免这个问题?
use*_*342 93
您可以将异常类型,值和回溯存储在局部变量中,并使用以下三参数形式raise:
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
raise t, v, tb
Run Code Online (Sandbox Code Playgroud)
在Python 3中,回溯存储在异常中,因此raise e将执行(大多数)正确的操作:
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e
Run Code Online (Sandbox Code Playgroud)
上面唯一的问题是它会产生一个稍微误导性的回溯,告诉你SomeError在处理过程中发生的事情AlsoFailsError(因为raise e内部except AlsoFailsError),实际上几乎完全相反的情况发生了 - 我们AlsoFailsError在尝试恢复时处理SomeError.要禁用此行为并获取从未提及的回溯AlsoFailsError,请替换raise e为raise e from None.
Lau*_*RTE 16
即使接受的解决方案是正确的,也可以指向具有Python 2 + 3解决方案的Six库six.reraise.
六.重新加载(exc_type,exc_value,exc_traceback = None)
重新引发异常,可能使用不同的回溯.[...]
所以,你可以写:
import six
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
six.reraise(t, v, tb)
Run Code Online (Sandbox Code Playgroud)
根据Drew McGowen的建议,但是处理一般情况(存在返回值s),这里是user4815162342答案的替代方案:
try:
s = something()
except SomeError as e:
def wrapped_plan_B():
try:
return False, plan_B()
except:
return True, None
failed, s = wrapped_plan_B()
if failed:
raise
Run Code Online (Sandbox Code Playgroud)
Python 3.5+ 无论如何都会将回溯信息附加到错误中,因此不再需要单独保存它。
>>> def f():
... try:
... raise SyntaxError
... except Exception as e:
... err = e
... try:
... raise AttributeError
... except Exception as e1:
... raise err from None
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in f
File "<stdin>", line 3, in f
SyntaxError: None
>>>
Run Code Online (Sandbox Code Playgroud)