简体   繁体   English

在 python 3 中禁用异常链接

[英]Disable exception chaining in python 3

There is a new feature that was introduced in python3 - exception chaining. python3 中引入了一个新特性——异常链接。 For some reasons I need to disable it for certain exceptions in my code.由于某些原因,我需要为代码中的某些异常禁用它。

Here is sample code:这是示例代码:

try:
    print(10/0)
except ZeroDivisionError as e:
    sys.exc_info()
    raise AssertionError(str(e))

what I see:我所看到的:

Traceback (most recent call last):
  File "draft.py", line 19, in main
    print(10/0)
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "draft.py", line 26, in <module>
    main()
  File "draft.py", line 22, in main
    raise AssertionError(str(e))
AssertionError: division by zero

what I want to see:我想看到的:

Traceback (most recent call last):
  File "draft.py", line 26, in <module>
    main()
  File "draft.py", line 22, in main
    raise AssertionError(str(e))
AssertionError: division by zero

I tried to use sys.exc_clear() , but this method is removed from python 3 too.我尝试使用sys.exc_clear() ,但此方法也已从 python 3 中删除。 I can use workaround that works我可以使用可行的解决方法

exc = None
try:
    print(10/0)
except ZeroDivisionError as e:
    exc = e
if exc:
    raise AssertionError(str(exc))

but I believe that there is better solution.但我相信有更好的解决方案。

Simple Answer简单的答案

try:
    print(10/0)
except ZeroDivisionError as e:
    raise AssertionError(str(e)) from None

However, you probably actually want:但是,您可能实际上想要:

try:
    print(10/0)
except ZeroDivisionError as e:
    raise AssertionError(str(e)) from e

Explanation解释

__cause__

Implicit exception chaining happens through __context__ when there isn't an explicit cause exception set.当没有明确的原因异常集时,隐式异常链接通过__context__发生。

Explicit exception chaining works through __cause__ so if you set __cause__ to the exception itself, it should stop the chaining.显式异常链接通过__cause__工作,因此如果您将__cause__设置为异常本身,它应该停止链接。 If __cause__ is set, Python will suppress the implicit message.如果设置了__cause__ ,Python 将抑制隐式消息。

try:
    print(10/0)
except ZeroDivisionError as e:
    exc = AssertionError(str(e))
    exc.__cause__ = exc
    raise exc

raise from

We can use "raise from" to do the same thing:我们可以使用“raise from”来做同样的事情:

try:
    print(10/0)
except ZeroDivisionError as e:
    exc = AssertionError(str(e))
    raise exc from exc

None __cause__没有__cause__

Setting __cause__ to None actually does the same thing:__cause__设置为None实际上做同样的事情:

try:
    print(10/0)
except ZeroDivisionError as e:
    exc = AssertionError(str(e))
    exc.__cause__ = None
    raise exc

raise from None从无提高

So that brings us to the most elegant way to do this which is to raise from None :所以这给我们带来了最优雅的方式来做到这一点,即None提出

try:
    print(10/0)
except ZeroDivisionError as e:
    raise AssertionError(str(e)) from None

But I would argue that you usually want to explicitly raise your exception from the cause exception so the traceback is preserved:但我认为您通常希望从原因异常中显式引发异常,以便保留回溯:

try:
    print(10/0)
except ZeroDivisionError as e:
    raise AssertionError(str(e)) from e

This will give us a slightly different message that states that the first exception was the direct cause of the second:这将给我们一个稍微不同的消息,指出第一个异常是第二个异常的直接原因:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
AssertionError: division by zero

There is a new feature that was introduced in python3 - exception chaining. python3 中引入了一个新特性——异常链接。 For some reasons I need to disable it for certain exceptions in my code.由于某些原因,我需要针对代码中的某些异常禁用它。

Here is sample code:这是示例代码:

try:
    print(10/0)
except ZeroDivisionError as e:
    sys.exc_info()
    raise AssertionError(str(e))

what I see:我所看到的:

Traceback (most recent call last):
  File "draft.py", line 19, in main
    print(10/0)
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "draft.py", line 26, in <module>
    main()
  File "draft.py", line 22, in main
    raise AssertionError(str(e))
AssertionError: division by zero

what I want to see:我想看到的:

Traceback (most recent call last):
  File "draft.py", line 26, in <module>
    main()
  File "draft.py", line 22, in main
    raise AssertionError(str(e))
AssertionError: division by zero

I tried to use sys.exc_clear() , but this method is removed from python 3 too.我尝试使用sys.exc_clear() ,但此方法也已从 python 3 中删除。 I can use workaround that works我可以使用有效的解决方法

exc = None
try:
    print(10/0)
except ZeroDivisionError as e:
    exc = e
if exc:
    raise AssertionError(str(exc))

but I believe that there is better solution.但我相信有更好的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM