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
最后修改: 2025-02-01 08:59:27 GMT