Python 中 raise 和 raise/from 的区别

Python 中 raise 和 raise/from 的使用方法



0. 参考资料


1. 代码比较

今天在看《Effective Python》的时候第一次见到 raise A from B 的用法,所以在网上查了一下。
下面用代码比较一下 raiseraise/from 的区别。

  • raise.py
# raise
try:
    raise ValueError
except Exception as e:
    raise IndexError
"""
Traceback (most recent call last):
  File "raise.py", line 3, in <module>
    raise ValueError
ValueError

During handling of the above exception, another exception occurred:

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

  • raisefrom.py
# raise/from
try:
    raise ValueError
except Exception as e:
    raise IndexError from e
"""
Traceback (most recent call last):
  File "raisefrom.py", line 3, in <module>
    raise ValueError
ValueError

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

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

上面的 raiseraise/from 都是放在 except 异常处理块中的。
可以观察到 raiseraise/from 最大的区别是异常提示信息不一样:

  • raise 是:During handling of the above exception, another exception occurred:
    即“在处理上面的异常时,发生了另外一个异常:”。
  • raise/from 是:The above exception was the direct cause of the following exception:
    即“上面的异常是接下来的异常的直接原因:”。

2. 用法解释

2.1 raise

当在 except 块或者 finally 块中出现异常时(包括使用单独的 raise 重新抛出异常的情况),之前的异常会被附加到新异常的 __context__ 属性上

except 块中的语句叫做异常处理器 exception handler,它们是处理异常的语句。

而在其他任何地方抛出异常,都不会设置 __context__ 属性。
这样打印出来的异常信息就会包含这么一句话:During handling of the above exception, another exception occurred:


2.2 raise A from B

raise A from B 语句用于连锁 chain 异常。
from 后面的 B 可以是:

  • 异常类
  • 异常实例
  • NonePython 3.3 的新特性)

如果 B 是异常类或者异常实例,那么 B 会被设置为 A__cause__ 属性,表明 A异常 是由 B异常 导致的。
这样打印出来的异常信息就会包含这样一句话:The above exception was the direct cause of the following exception:
与此同时,在 Python 3.3A异常__suppress_context__ 属性会被设置为 True,这样就抑制A异常__context__ 属性,即忽略 __context__ 属性。
于是 Python不会自动打印异常上下文 exception context,而是使用 __cause__ 属性来打印异常的引发者。

Python 3.3 中,B 还可以是 Noneraise A异常 from None
这样相当于把 __suppress_context__ 属性设置为 True,从而禁用了 __context__ 属性,Python 不会自动展示异常上下文。
比如下面这段代码,注意到只显示了 IndexError 一个异常信息:
raisefromnone.py

# raise ... from None
# 禁用异常上下文属性
try:
    raise ValueError
except Exception as e:
    raise IndexError from None
"""
Traceback (most recent call last):
  File "raisefromnone.py", line 6, in <module>
    raise IndexError from None
IndexError
"""


3. 总结

except 或者 finally 块中使用 raiseraise/from 语句需要注意:

扫描二维码关注公众号,回复: 4173973 查看本文章
  • raise 会设置后面异常的 __context__ 属性为前面的异常。
    异常信息中会有 During handling of the above exception, another exception occurred:
  • raise A异常 from B异常 会把 A异常__cause__ 属性设置为 B异常
    同时设置 __suppress_context__ 属性为 True,从而忽略 __context__ 属性,不打印异常上下文信息。
    异常信息中会有 The above exception was the direct cause of the following exception:
  • raise A异常 from None 会设置 A异常__suppress_context__ 属性为 True,这样会忽略它的 __context__ 属性,不会自动显示异常上下文信息。

完成于 2018.11.21

猜你喜欢

转载自blog.csdn.net/jpch89/article/details/84315444