Mar*_*ica 10 python exception raise python-2.7 python-3.x
Python的文档说:
如果不存在任何表达式,请
raise重新引发当前作用域中活动的最后一个异常。
(Python 3:https://docs.python.org/3/reference/simple_stmts.html#raise; Python 2.7:https://docs.python.org/2.7/reference/simple_stmts.html#raise。)
但是,“上次激活”的概念似乎已经改变。见证以下代码示例:
#
from __future__ import print_function
import sys
print('Python version =', sys.version)
try:
raise Exception('EXPECTED')
except:
try:
raise Exception('UNEXPECTED')
except:
pass
raise # re-raises UNEXPECTED for Python 2, and re-raises EXPECTED for Python 3
Run Code Online (Sandbox Code Playgroud)
这会导致我在Python 2中出乎意料的事情:
Python version = 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)]
Traceback (most recent call last):
File "./x", line 10, in <module>
raise Exception('UNEXPECTED')
Exception: UNEXPECTED
Run Code Online (Sandbox Code Playgroud)
但使用Python 3有预期的结果(对我而言):
Python version = 3.6.8 (default, Feb 14 2019, 22:09:48)
[GCC 7.4.0]
Traceback (most recent call last):
File "./x", line 7, in <module>
raise Exception('EXPECTED')
Exception: EXPECTED
Run Code Online (Sandbox Code Playgroud)
和
Python version = 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)]
Traceback (most recent call last):
File "./x", line 7, in <module>
raise Exception('EXPECTED')
Exception: EXPECTED
Run Code Online (Sandbox Code Playgroud)
那么“最后一个...活动”是什么意思?是否有一些有关此重大更改的文档?还是这是Python 2错误?
更重要的是:在Python 2中实现此功能的最佳方法是什么?(最好使代码能够在Python 3中正常工作。)
请注意,如果将代码更改为
Python version = 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)]
Traceback (most recent call last):
File "./x", line 10, in <module>
raise Exception('UNEXPECTED')
Exception: UNEXPECTED
Run Code Online (Sandbox Code Playgroud)
然后事情也开始适用于Python 2:
Python version = 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)]
Traceback (most recent call last):
File "./x", line 13, in <module>
raise Exception('EXPECTED')
Exception: EXPECTED
Run Code Online (Sandbox Code Playgroud)
我正在考虑改用...
Python 2 的行为与其说是错误,不如说是设计缺陷。Python 3.0 通过添加异常链功能解决了这个问题。与此更改的文档最接近的内容可以在PEP 3134 — 异常链和嵌入式回溯 动机中找到:
在处理一个异常(异常A)的过程中,有可能发生另一异常(异常B)。在今天的Python(版本2.4)中,如果发生这种情况,异常B会向外传播,异常A会丢失。
这正是您在 2.7 中看到的情况:EXPECTED (A) 丢失,因为 UNEXPECTED (B) 出现并覆盖了它。借助 Python 3 中较新的异常链接功能,可以通过异常实例上的__cause__和属性来保留两个错误的完整上下文。__context__
对于更直接的交叉兼容解决方法,我鼓励您手动保留引用,明确显示正在重新引发的错误,并像往常一样避免裸except语句(它们总是太宽泛):
try:
raise Exception('EXPECTED')
except Exception as err_expected:
try:
raise Exception('UNEXPECTED')
except Exception as err_unexpected:
pass
raise err_expected
Run Code Online (Sandbox Code Playgroud)
如果您希望以交叉兼容的方式抑制异常链接功能,可以通过err_expected.__cause__ = None在重新引发之前进行设置来实现。
| 归档时间: |
|
| 查看次数: |
248 次 |
| 最近记录: |