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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18188563/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 10:08:13  来源:igfitidea点击:

How to re-raise an exception in nested try/except blocks?

pythonexceptionnestedraise

提问by Tobias Kienzler

I know that if I want to re-raise an exception, I simple use raisewithout arguments in the respective exceptblock. But given a nested expression like

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

how can I re-raise the SomeErrorwithout breaking the stack trace? raisealone would in this case re-raise the more recent AlsoFailsError. Or how could I refactor my code to avoid this issue?

如何在SomeError不破坏堆栈跟踪的情况下重新提高?raise在这种情况下,单独会重新加注最近的AlsoFailsError。或者我如何重构我的代码以避免这个问题?

采纳答案by user4815162342

You can store the exception type, value, and traceback in local variables and use the three-argument form of raise:

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

try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        raise t, v, tb

In Python 3 the traceback is stored in the exception, so raise ewill do the (mostly) right thing:

在 Python 3 中,回溯存储在异常中,因此raise e会做(大部分)正确的事情:

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

Note that the traceback produced by Python 3 will include a message that SomeErroroccurred while handling AlsoFailsError(because of raise ebeing inside except AlsoFailsError). This is misleading because what actually happened is the other way around - we handled AlsoFailsErrorwhile trying to recover from SomeError. To obtain a traceback that doesn't include AlsoFailsError, as was the default in Python 2, replace raise ewith raise e from None.

请注意,Python 3 生成的回溯将包括SomeError处理时发生的消息AlsoFailsError(因为raise e在 inside except AlsoFailsError)。这是一种误导,因为实际发生的事情是相反的 - 我们AlsoFailsError在尝试从SomeError. 要获得不包含 的回溯AlsoFailsError(Python 2 中的默认设置),请替换raise eraise e from None.

回答by Tobias Kienzler

As per Drew McGowen's suggestion, but taking care of a general case (where a return value sis present), here's an alternative to user4815162342's answer:

根据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

回答by Matthias Urlichs

Python 3.5+ attaches the traceback information to the error anyway, so it's no longer necessary to save it separately.

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
>>> 

回答by Laurent LAPORTE

Even if the accepted solutionis right, it's good to point to the Sixlibrary which has a Python 2+3 solution, using six.reraise.

即使接受的解决方案是正确的,最好指向具有 Python 2+3 解决方案的Six库,使用six.reraise.

six.reraise(exc_type, exc_value, exc_traceback=None)

Reraise an exception, possibly with a different traceback. [...]

六。重新加注exc_typeexc_valueexc_traceback=None)

重新引发异常,可能具有不同的回溯。[...]

So, you can write:

所以,你可以写:

import six


try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        six.reraise(t, v, tb)