Python“提高”用法


196

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

9
你读过PEP-3134吗?
jonrsharpe 2014年

4
现在使用raise IndexError from None,说。
马丁·皮特斯

11
h raise IndexError from False引发一个TypeError,而不是一个IndexError。让我开心。
疯狂物理学家,2013年


不知道这里是否合适,但对于使用Spyder的任何人来说:整个结构在那里不起作用。三年多来一直是一个问题(github.com/spyder-ide/spyder/issues/2943),但是他们似乎认为不需要链式异常。
Emil Bode

Answers:


227

区别在于,当您使用时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

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


11
是否有任何理由使用from__cause__代替隐式来显式链接异常__context__?在任何情况下,有人会附上与被捕获者不同的例外except吗?
darkfeline 2014年

13
@darkfeline:可以说您的数据库API支持从各种来源(包括Web和磁盘)打开数据库。如果打开数据库失败,您的API将始终引发a DatabaseError。但是,如果失败是IOError由于文件打开失败或HTTPErrorURL无法运行而导致的,那么您要明确包含上下文,因此使用API​​的开发人员可以调试原因。那时您使用raise DatabaseError from original_exception
马丁·彼得斯

4
@darkfeline:如果开发商包装使用的数据库API在自己的API,并想通过上IOErrorHTTPError他们的消费者,那么他们必须使用raise NewException from databaseexception.__cause__,现在用的是不同的异常从DatabaseException他们刚刚捕获。
马丁·彼得斯

2
@ dan3:不,没有。异常链接纯粹是Python 3的功能。
马丁·彼得斯

5
@ laike9m:您的意思是在处理异常时foo,想引发新的异常bar?然后,您可以使用raise bar from foofoo 直接导致bar Python状态。如果你使用from foo,那么Python仍然会同时打印,但状态过程中的处理foobar有人提出,不同的消息,意在国旗在错误处理可能的错误。
马丁·彼得斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.