PEP 473 – 为内置异常添加结构化数据
- 作者:
- Sebastian Kreft <skreft at deezer.com>
- 状态:
- 已拒绝
- 类型:
- 标准跟踪
- 创建:
- 2014年3月29日
- 发布历史:
- 决议:
- Python-Dev 消息
摘要
像 AttributeError
、IndexError
、KeyError
、LookupError
、NameError
、TypeError
和 ValueError
这样的异常并没有提供程序员调试和更好地理解导致它们的原因所需的所有信息。此外,在某些情况下,消息甚至具有略微不同的格式,这使得工具难以自动提供其他信息来诊断问题。为了解决前者并为后者奠定基础,建议扩展这些异常,以便同时保存违规实体和受影响实体。
基本原理
此 PEP 旨在解决的主要问题是,当前错误消息不够表达,缺乏解决异常的一些关键信息。此外,错误消息中提供的信息并不总是采用相同的格式,这使得第三方库很难自动诊断错误。
例如,这些自动化工具可以检测拼写错误或显示或记录额外的调试信息。在运行测试或在长时间运行的应用程序中,这些可能特别有用。
虽然从理论上讲,拥有此类库是可能的,但它们需要借助一些技巧才能实现目标。其中一个例子是 python-improved-exceptions [1],它修改字节码以保留对可能有趣的对象的引用,并解析错误消息以提取类型或名称等信息。不幸的是,这种方法极其脆弱且不可移植。
类似的提案 [2] 已在 ImportError
中实现,并且同样地,这个想法也得到了支持 [3]。此外,大约 10 年前,Guido 在 [11] 中要求有一个干净的 API 来访问像 KeyError
、AttributeError
、NameError
和 IndexError
这样的异常中受影响的对象。在过去的一年中,也写过类似的问题和提案想法。创建了一些其他问题,但尽管得到了支持,最终还是被放弃了。下面列出了已创建问题的引用
AttributeError
: [11]、[10]、[5]、[4]、[3]IndexError
: [11]、[6]、[3]KeyError
: [11]、[7]、[3]LookupError
: [11]NameError
: [11]、[10]、[3]TypeError
: [8]ValueError
: [9]
为了推进开发并集中信息和讨论,此 PEP 旨在成为总结上述所有讨论和想法的元问题。
示例
IndexError
错误消息没有引用列表的长度或使用的索引。
a = [1, 2, 3, 4, 5]
a[5]
IndexError: list index out of range
KeyError
按照惯例,键是错误参数的第一个元素,但没有其他关于受影响字典的信息(键类型、大小等)。
b = {'foo': 1}
b['fo']
KeyError: 'fo'
AttributeError
对象的类型和违规属性是错误消息的一部分。但是,有一些不同的格式,并且信息并不总是可用。此外,尽管对象类型在某些情况下很有用,但鉴于 Python 的动态特性,拥有对对象本身的引用会更有用。此外,对类型的引用未完全限定,在某些情况下,类型过于通用,无法提供有用的信息,例如在访问模块的属性时。
c = object()
c.foo
AttributeError: 'object' object has no attribute 'foo'
import string
string.foo
AttributeError: 'module' object has no attribute 'foo'
a = string.Formatter()
a.foo
AttributeError: 'Formatter' object has no attribute 'foo'
NameError
错误消息通常提供名称。
foo = 1
fo
NameError: global name 'fo' is not defined
其他情况
当目标对象是另一个表达式的结果时,问题更难以调试,例如
a[b[c[0]]]
此问题也与操作码仅具有行号信息而不是偏移量这一事实有关。此提案在这种情况下会有所帮助,但不如具有偏移量那么有效。
提案
扩展异常 AttributeError
、IndexError
、KeyError
、LookupError
、NameError
、TypeError
和 ValueError
,如下所示
AttributeError
: target w、attributeIndexError
: target w、key w、index(只是 key 的别名)KeyError
: target w、key wLookupError
: target w、key wNameError
: name、scope?TypeError
: unexpected_typeValueError
: unexpected_value w
带有上标 w 的属性可能需要弱引用 [12] 以防止任何内存循环。但是,正如 R. David Murray 所指出的 [13],这可能会增加不必要的额外复杂性。鉴于内置类型不支持弱引用,这一点尤其如此。
TODO(skreft):用异常情况的示例扩展此内容。
为了保持向后兼容性,这些新属性将是可选的并且仅限于关键字。
建议添加此信息,而不仅仅是改进错误,因为前者将允许新的调试框架和工具,并且将来还可以切换到延迟生成的错误消息。延迟生成的消息在 [2] 中有讨论,尽管目前尚未实现。它们不仅可以节省一些资源,还可以统一消息。
然后将逐步更改标准库以开始使用这些新属性。
潜在用途
例如,自动化工具可以搜索对象中类似的键,从而显示以下内容:
a = {'foo': 1}
a['fo']
KeyError: 'fo'. Did you mean 'foo'?
foo = 1
fo
NameError: global name 'fo' is not defined. Did you mean 'foo'?
有关 TestRunner 可以显示的输出,请参见 [3]。
性能
填充这些新属性只需要两个带有已可用数据的额外参数,因此影响应该很小。但是,对于 KeyError
可能需要特别注意,因为以下模式已经很普遍。
try:
a[foo] = a[foo] + 1
except:
a[foo] = 0
还要注意,将这些对象存储到错误本身中将允许延迟生成错误消息,如 [2] 中所述。
参考文献
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0473.rst
上次修改时间:2023年9月9日 17:39:29 GMT