Python“提高”用法

问题:Python“提高”用法

raiseraise fromPython 和有什么不一样?

try:
    raise ValueError
except Exception as e:
    raise IndexError

产生

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

try:
    raise ValueError
except Exception as e:
    raise IndexError from e

产生

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

What’s the difference between raise and raise from in Python?

try:
    raise ValueError
except Exception as e:
    raise IndexError

which yields

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

and

try:
    raise ValueError
except Exception as e:
    raise IndexError from e

which yields

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

回答 0

区别在于,当您使用时from,会设置__cause__属性,并且消息会指出异常是由引起的。如果您省略,from__cause__设置no ,但是也可以设置该__context__属性,然后回溯显示上下文,就像处理其他事件时一样

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

如果__cause__设置了a,那么__suppress_context__ = True还会在异常上设置一个标志;当__suppress_context__设置为时,在打印回溯时True__context__忽略。

从异常处理程序,你养的时候希望显示上下文(不想处理另一个异常发生时,然后用消息)raise ... from None来设置__suppress_context__True

换句话说,Python 在异常上设置了一个上下文,因此您可以自省引发异常的位置,让您查看是否用它替换了另一个异常。您还可以将原因添加到异常中,使回溯明确地显示其他异常(使用不同的措辞),并且上下文将被忽略(但在调试时仍可以自省)。使用raise ... from None使您可以禁止打印上下文。

请参阅raise语句documenation

from子句用于异常链接:如果给定,则第二个表达式必须是另一个异常类或实例,然后将其作为__cause__属性(可写)附加到引发的异常上。如果未处理引发的异常,则将打印两个异常:

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

如果在异常处理程序或finally子句中引发异常,则类似的机制会隐式工作:然后,将先前的异常附加为新异常的__context__属性:

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

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

The difference is that when you use from, the __cause__ attribute is set and the message states that the exception was directly caused by. If you omit the from then no __cause__ is set, but the __context__ attribute may be set as well, and the traceback then shows the context as during handling something else happened.

Setting the __context__ happens if you used raise in an exception handler; if you used raise anywhere else no __context__ is set either.

If a __cause__ is set, a __suppress_context__ = True flag is also set on the exception; when __suppress_context__ is set to True, the __context__ is ignored when printing a traceback.

When raising from a exception handler where you don’t want to show the context (don’t want a during handling another exception happened message), then use raise ... from None to set __suppress_context__ to True.

In other words, Python sets a context on exceptions so you can introspect where an exception was raised, letting you see if another exception was replaced by it. You can also add a cause to an exception, making the traceback explicit about the other exception (use different wording), and the context is ignored (but can still be introspected when debugging). Using raise ... from None lets you suppress the context being printed.

See the raise statement documenation:

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:

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

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

Also see the Built-in Exceptions documentation for details on the context and cause information attached to exceptions.