如何在嵌套的try / except块中重新引发异常?

时间:2013-08-12 13:42:40

标签: python exception nested 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

如何在不破坏堆栈跟踪的情况下重新引发SomeError?在这种情况下,仅raise就会重新提升最近的AlsoFailsError。或者我怎么能重构我的代码以避免这个问题呢?

4 个答案:

答案 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 eexcept 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
>>>