简体   繁体   English

如何以与 Python 2 和 3 兼容的方式在没有异常链接的情况下在 except 块内引发异常?

[英]How do you raise an exception inside an except block without exception chaining in a way that's compatible with both Python 2 and 3?

In Python 2.7, the following will only print one traceback, from the exception raised in the except block:在 Python 2.7 中,以下将仅打印一个回溯,来自except块中引发的异常:

try:
   1/0
except ZeroDivisionError:
   raise Exception("Error!")

Output: Output:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
Exception: Error!

However in Python 3 there is exception chaining.但是在 Python 3 中存在异常链接。 Here is the output for the same code:这是相同代码的 output:

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

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
Exception: Error!

I need to write some code that is compatible with both Python 2.7 and Python 3, and I need for there to be no exception chaining when the exception is raised inside that except block.我需要编写一些与 Python 2.7 和 Python 3 兼容的代码,并且当在该except块内引发异常时,我需要没有异常链接 So that the output will be what you see above when that code is executed in Python 2.7.因此,当在 Python 2.7 中执行该代码时,output 将是您在上面看到的。

The one possible solution I've found is raise_from , included in the six module:我发现的一种可能的解决方案是raise_from ,包含在six模块中:

from six import raise_from
try:
   1/0
except ZeroDivisionError:
   raise_from(Exception("Error!"), None)

However, it adds an extra line for raise_from to the traceback that I'd like to avoid:但是,它在我想避免的回溯中为raise_from添加了额外的一行:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "<string>", line 3, in raise_from
Exception: Error!

Is there any way to do this?有没有办法做到这一点?

The following produces identical output on py2.7.13 and py3.9.2, if you call it with the full path.如果您使用完整路径调用它,以下会在 py2.7.13 和 py3.9.2 上生成相同的 output。 (If you use a relative path, py3 expands it, but py2 does not.) (如果使用相对路径,py3 会扩展它,但 py2 不会。)

try:
    1/0
except ZeroDivisionError:
    internal = Exception("Error!")
    internal.__suppress_context__ = True
    raise internal

Traceback (most recent call last):回溯(最近一次通话最后):
File "b:\development\python\so.py", line 6, in文件“b:\development\python\so.py”,第 6 行,在
raise internal提高内部
Exception: Error!例外:错误!

I was hoping to avoid internal attributes that might change, but __suppress_context__ is documented https://docs.python.org/3/library/exceptions.html我希望避免可能更改的内部属性,但 __suppress_context__ 已记录在案 https://docs.python.org/3/library/exceptions.ZFC35FDC70D5FC69D2698Z83A822C7A5E3

Use a finally block to discard the context after the exception was raised:在引发异常后,使用finally块丢弃上下文:

try:
   1/0
except ZeroDivisionError:
   # store exception to allow modifying it
   exc = Exception("Error!")
   try:
       raise exc
   finally:
       # context has been set here already – discard it
       exc.__context__ = None

This also works in Python2 for any proper exception, ie those derived from BaseException .这在 Python2 中也适用于任何适当的异常,即那些从BaseException派生的异常。

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

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