问题:如何在嵌套的try / except块中重新引发异常?
我知道如果我想重新引发异常,我会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
。或者我该如何重构我的代码来避免此问题?
I know that if I want to re-raise an exception, I simple use raise
without arguments in the respective except
block. But given a nested expression like
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 SomeError
without breaking the stack trace? raise
alone would in this case re-raise the more recent AlsoFailsError
. Or how could I refactor my code to avoid this issue?
回答 0
从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 e
为raise 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
As of Python 3 the traceback is stored in the exception, so a simple raise e
will do the (mostly) right thing:
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e # or raise e from None - see below
The traceback produced will include an additional notice that SomeError
occurred while handling AlsoFailsError
(because of raise e
being inside except AlsoFailsError
). This is misleading because what actually happened is the other way around – we encountered AlsoFailsError
, and handled it, while trying to recover from SomeError
. To obtain a traceback that doesn’t include AlsoFailsError
, replace raise e
with raise e from None
.
In Python 2 you’d store the exception type, value, and traceback in local variables and use the three-argument form of raise
:
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
raise t, v, tb
回答 1
即使接受的解决方案正确,也最好使用指向具有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)
Even if the accepted solution is right, it’s good to point to the Six library which has a Python 2+3 solution, using six.reraise
.
six.reraise(exc_type, exc_value, exc_traceback=None)
Reraise an exception, possibly with a different traceback.
[…]
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)
回答 2
根据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
As per Drew McGowen’s suggestion, but taking care of a general case (where a return value s
is present), here’s an alternative to 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
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
>>>
Python 3.5+ attaches the traceback information to the error anyway, so it’s no longer necessary to save it separately.
>>> 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
>>>