151

我知道,如果我想重新引发异常,我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

4 回答 4

175

从 Python 3 开始,回溯存储在异常中,所以一个简单raise e的操作(大部分)是正确的:

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e  # or raise e from None - see below

SomeError产生的回溯将包括在处理时发生的附加通知AlsoFailsError(因为raise e在里面except AlsoFailsError)。这是误导性的,因为实际发生的情况恰恰相反——我们AlsoFailsError在试图从中恢复时遇到并处理了它SomeError。要获取不包含 的回溯AlsoFailsError,请替换raise eraise e from None.

在 Python 2 中,您可以将异常类型、值和回溯存储在局部变量中,并使用以下三参数形式raise

try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        raise t, v, tb
于 2013-08-12T13:47:35.340 回答
24

即使公认的解决方案是正确的,也最好指出具有 Python 2+3 解决方案的Sixsix.reraise库,使用.

六。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)
于 2017-09-28T10:27:19.073 回答
15

根据Drew McGowen 的建议,但要考虑一般情况(存在返回值),这是user4815162342 的答案s的替代方案:

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
于 2013-08-12T14:10:33.937 回答
7

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
>>> 
于 2017-04-25T08:25:27.960 回答