PEP 232 – 函数属性
- 作者:
- Barry Warsaw <barry at python.org>
- 状态:
- 最终版
- 类型:
- 标准跟踪
- 创建日期:
- 2000年12月2日
- Python 版本:
- 2.1
- 发布历史:
- 2001年2月20日
引言
本PEP描述了Python的一项扩展,为函数和方法添加了属性字典。本PEP跟踪此功能的现状和所有权。它包含对该功能的描述,并概述了支持该功能所需的更改。本PEP总结了邮件列表论坛中的讨论,并在适当之处提供了更多信息的URL。此文件的CVS修订历史记录包含权威的历史记录。
背景
函数已经具有许多属性,其中一些是可写的,例如func_doc,也就是func.__doc__。func_doc有一个有趣的特性,即在函数(和方法)定义中有特殊的语法用于隐式设置该属性。这种便利性被一再利用,用额外的语义来重载文档字符串。
例如,John Aycock编写了一个系统,其中文档字符串用于定义解析规则。[1] Zope的ZPublisher ORB [2] 使用文档字符串来标记可发布的方法,即可以通过Web调用的方法。
这种方法的问题是,重载的语义可能相互冲突。例如,如果我们要向一个Zope方法添加一个doctest单元测试,但该方法不应通过Web发布。
提案
本提案向函数对象添加了一个新的字典,名为func_dict(又名__dict__)。这个字典可以使用普通的属性设置和获取语法进行设置和获取。
方法也获得了获取器语法,它们目前通过底层函数对象的字典访问属性。不可能在绑定或未绑定方法上设置属性,除非明确地在底层函数对象上进行设置。请参阅下面的未来方向讨论,了解Python后续版本中的方法。
函数对象的__dict__也可以设置,但只能设置为字典对象。删除函数的__dict__,或将其设置为除具体字典对象之外的任何内容,都会导致TypeError。如果从未设置过函数属性,则函数的__dict__将为空。
示例
以下是使用此功能的一些示例。
def a():
pass
a.publish = 1
a.unittest = '''...'''
if a.publish:
print a()
if hasattr(a, 'unittest'):
testframework.execute(a.unittest)
class C:
def a(self):
'just a docstring'
a.publish = 1
c = C()
if c.a.publish:
publish(c.a())
其他用途
Paul Prescod 在 python-dev 线程中列举了许多其他用途。
未来方向
以下是需要考虑的一些未来方向。任何采纳这些想法都需要一个新的PEP,该PEP将引用本PEP,并且必须针对2.1版本之后的Python版本。
- 本PEP的先前版本允许在未绑定方法上同时设置和获取属性,而仅在绑定方法上允许获取属性。此策略中发现了一些问题。
因为方法属性存储在底层函数中,这导致了一些可能令人惊讶的结果
class C: def a(self): pass c1 = C() c2 = C() c1.a.publish = 1 # c2.a.publish would now be == 1 also!
由于对绑定到
c1的a的更改也会导致对绑定到c2的a的更改,因此禁止在绑定方法上设置属性。然而,即使允许在未绑定方法上设置属性也存在其模糊性class D(C): pass class E(C): pass D.a.publish = 1 # E.a.publish would now be == 1 also!
因此,当前的PEP禁止在绑定或未绑定方法上设置属性,但允许在这两者上获取属性——两者都返回底层函数对象上的属性值。
未来的PEP可能会提议通过使用特殊命名约定在实例或类上设置属性来实现设置(绑定或未绑定)方法属性。即
class C: def a(self): pass C.a.publish = 1 C.__a_publish__ == 1 # true c = C() c.a.publish = 2 c.__a_publish__ == 2 # true d = C() d.__a_publish__ == 1 # true
在这里,实例上的查找将首先查看实例的字典,然后是类的字典,最后是函数对象的字典。
- 目前,Python仅支持Python函数(即用Python编写的函数,而不是内置函数)的函数属性。如果值得,可以制作一个单独的补丁,为内置函数添加函数属性。
__doc__是目前唯一具有语法支持以便捷设置的函数属性。最终增强语言以支持轻松设置函数属性可能值得。以下是PEP审阅者建议的一些语法:[3]def a { 'publish' : 1, 'unittest': '''...''', } (args): # ... def a(args): """The usual docstring.""" {'publish' : 1, 'unittest': '''...''', # etc. } def a(args) having (publish = 1): # see reference [3] pass
BDFL目前反对任何此类用于设置任意函数属性的特殊语法支持。任何语法提案都必须在新PEP中概述。
异议
当此议题于2000年4月在python-dev邮件列表中讨论时,表达了一些不同意见。为完整起见,讨论线程始于python-dev。
异议似乎属于以下类别
- 目的不明确(它能为你带来什么?)
- 其他实现方式(例如,将映射作为类属性)
- 在包含语法支持之前无用
反驳其中一些论点的是,对于普通的Python 2.0,__doc__实际上可以设置为任何类型的对象,因此一些可写的函数属性已经可行。但这种方法是对__doc__的又一次破坏。
虽然当然可以将映射添加到类对象(或在函数属性的情况下,添加到函数的模块),但提取属性值进行检查更为困难且不那么明显。
最后,可能需要添加语法支持,就像__doc__存在语法支持一样。这可以与实际设置和获取函数属性的能力分开考虑。
参考实现
此PEP已被接受,并且其实现已集成到 Python 2.1 中。
参考资料
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0232.rst