Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 增强提案

PEP 232 – 函数属性

作者:
Barry Warsaw <barry at python.org>
状态:
最终
类型:
标准跟踪
创建:
2000-12-02
Python 版本:
2.1
历史记录:
2001-02-20

目录

简介

本 PEP 描述了对 Python 的扩展,为函数和方法添加属性字典。本 PEP 跟踪此功能的状态和所有权。它包含对该功能的描述,并概述了支持该功能所需的更改。本 PEP 总结了在邮件列表论坛中进行的讨论,并在适当的情况下提供了更多信息的 URL。该文件的 CVS 修订历史包含确定的历史记录。

背景

函数已经拥有多个属性,其中一些属性是可写的,例如 func_doc,又称 func.__doc__func_doc 具有一个有趣的属性,即在函数(和方法)定义中存在用于隐式设置属性的特殊语法。这种便利已被反复利用,用额外的语义重载文档字符串。

例如,John Aycock 编写了一个系统,其中文档字符串用于定义解析规则。 [1] Zope 的 ZPublisher ORB [2] 使用文档字符串来指示可发布的方法,即可以通过网络调用的方法。

这种方法的问题在于,重载的语义可能会相互冲突。例如,如果我们想为不应该通过网络发布的 Zope 方法添加 doctest 单元测试。

提议

本提议为函数对象添加一个新的字典,称为 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,并且必须针对 Python 2.1 版本之后的版本。

  • 此 PEP 的先前版本允许对未绑定方法进行属性的设置和获取,而对绑定方法仅进行获取。在该策略中发现了一些问题。

    由于方法属性存储在底层函数中,因此会导致一些潜在的意外结果

    class C:
        def a(self): pass
    
    c1 = C()
    c2 = C()
    c1.a.publish = 1
    # c2.a.publish would now be == 1 also!
    

    由于对绑定 c1a 的更改也会导致对绑定到 c2a 的更改,因此禁止对绑定方法设置属性。但是,即使允许对未绑定方法设置属性也会出现歧义

    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

最后修改时间:2023-09-09 17:39:29 GMT