Python“从使用中提升”

Python “raise from” usage

Python中raiseraise from之间有什么区别?

1
2
3
4
try:
    raise ValueError
except Exception as e:
    raise IndexError

产量

1
2
3
4
5
6
7
8
9
10
11
Traceback (most recent call last):
  File"tmp.py", line 2, in <module>
    raise ValueError
ValueError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File"tmp.py", line 4, in <module>
    raise IndexError
IndexError

1
2
3
4
try:
    raise ValueError
except Exception as e:
    raise IndexError from e

产量

1
2
3
4
5
6
7
8
9
10
11
Traceback (most recent call last):
  File"tmp.py", line 2, in <module>
    raise ValueError
ValueError

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

Traceback (most recent call last):
  File"tmp.py", line 4, in <module>
    raise IndexError from e
IndexError


不同之处在于,当您使用from时,会设置__cause__属性,并且消息指出异常是由直接引起的。如果省略from,则不设置__cause__,但也可以设置__context__属性,然后回溯会在处理其他事件时显示上下文。

如果在异常处理程序中使用raise,则会设置__context__;如果您在其他任何地方使用raise,则也不设置__context__

如果设置了__cause__,则还会在异常上设置__suppress_context__ = True标志;当__suppress_context__设置为True时,打印回溯时将忽略__context__

从异常处理程序引发时,您不希望显示上下文(不希望处理期间发生另一个异常消息),然后使用raise ... from None__suppress_context__设置为True

换句话说,Python在异常上设置了一个上下文,这样你就可以反省引发异常的位置,让你看看是否有另一个异常被它取代。您还可以向异常添加原因,使回溯显式关于另一个异常(使用不同的措辞),并忽略上下文(但在调试时仍然可以进行内省)。使用raise ... from None可以抑制正在打印的上下文。

请参阅raise声明文档:

The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable). If the raised exception is not handled, both exceptions will be printed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File"<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

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

Traceback (most recent call last):
  File"<stdin>", line 4, in <module>
RuntimeError: Something bad happened

A similar mechanism works implicitly if an exception is raised inside an exception handler or a finally clause: the previous exception is then attached as the new exception’s __context__ attribute:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File"<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File"<stdin>", line 4, in <module>
RuntimeError: Something bad happened

另请参阅内置异常文档,以获取有关上下文的详细信息以及附加到异常的原因信息。