我知道如果我想重新引发异常,我会在相应的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
如何在不破坏堆栈跟踪的情况下重新引发SomeError
?在这种情况下,仅raise
就会重新提升最近的AlsoFailsError
。或者我怎么能重构我的代码以避免这个问题呢?
答案 0 :(得分:84)
您可以将异常类型,值和回溯存储在局部变量中,并使用three-argument form of raise
:
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
raise t, v, tb
在Python 3中,回溯存储在异常中,因此raise e
将执行(大多数)正确的操作:
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e
上述唯一的问题是,它会产生一个误导性的回溯,告诉您在处理SomeError
时发生了AlsoFailsError
(由于raise e
内except AlsoFailsError
) ,实际上几乎完全相反 - 我们在尝试从AlsoFailsError
恢复时处理了SomeError
。要禁用此行为并获取从未提及AlsoFailsError
的追溯,请将raise e
替换为raise e from None
。
答案 1 :(得分:12)
即使accepted solution是正确的,使用Six指向具有Python 2 + 3解决方案的six.reraise
库也不错。
六。重新加入( exc_type , exc_value , exc_traceback =无)
重新加载异常,可能使用不同的回溯。 [...]
所以,你可以写:
import six
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
six.reraise(t, v, tb)
答案 2 :(得分:7)
根据Drew McGowen's suggestion,但是要处理一般情况(返回值s
存在的情况下),这里是user4815162342's answer的替代方法:
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
答案 3 :(得分:3)
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
>>>