Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 549 – 实例描述符

作者:
Larry Hastings <larry at hastings.org>
讨论至:
Python-Dev 列表
状态:
已拒绝
类型:
标准跟踪
创建日期:
2017年9月4日
Python 版本:
3.7
发布历史:
2017年9月4日

目录

拒绝通知

https://mail.python.org/pipermail/python-dev/2017-November/150528.html

摘要

Python 的描述符协议要求描述符必须是对象类型的成员。本 PEP 提议扩展描述符协议,允许将描述符协议用于实例的成员。这将允许在模块中使用属性。

基本原理

Python 的描述符协议引导程序员进行优雅的 API 设计。如果你的类支持一个类似数据的成员,并且你将来可能需要在更改成员值时运行代码,那么你现在可以简单地将其声明为类的普通数据成员。如果将来确实需要运行代码,你可以将其更改为“属性”,并且 API 不会发生变化。

但请考虑 Python API 设计的第二个最佳实践:如果你正在编写一个单例,不要编写一个类,直接将你的代码构建到模块中。不要让你的用户实例化一个单例类,也不要让你的用户必须通过存储在模块中的单例对象进行解引用,只需拥有模块级别的函数和模块级别的数据。

不幸的是,这两个最佳实践是相互冲突的。问题在于属性不支持在模块上。模块是单个通用 module 类型的实例,无法修改或子类化该类型来向其模块添加属性。这意味着面临此 API 设计决策(其中类似数据成员是存储在模块中的单例)的程序员必须预先添加丑陋的“getter”和“setter”来处理数据。

纯 Python 中添加对模块属性的支持最近才成为可能;从 Python 3.5 开始,Python 允许为此目的将值赋给模块对象的 __class__ 属性。以下是一个使用此功能向模块添加属性的示例:

import sys, types
class _MyModuleType(types.ModuleType):
    @property
    def prop(self, instance, owner):
        ...

sys.modules[__name__].__class__ = _MyModuleType

这可行,并且是受支持的行为,但它笨拙且晦涩。

本 PEP 提议对描述符协议进行每个类型选择加入的扩展,该扩展专门用于在模块中启用属性。该机制是一种在成员未声明为类变量的情况下,为类的实例的成员遵循描述符协议的方法。

尽管这被提议为一个通用机制,但作者目前只预见到它对模块对象有用。

实施

基本思想很简单:修改由 PyModule_Type 公开的 tp_descr_gettp_descr_set 函数,以检查交互的属性,如果它支持描述符协议,则调用相关的公开函数。

我们的实现面临两个挑战:

  1. 由于每次查找方法上的属性时都会运行此代码,因此在一般情况下(属性中存储的对象不是描述符),它需要增加非常少的开销。
  2. 由于函数是描述符,我们必须小心不要为所有对象遵循描述符协议。否则,所有模块级别的函数将突然绑定到模块实例,就像它们是对模块对象的方法调用一样。模块句柄将作为“self”参数传递给所有模块级别的函数。

这两个挑战都可以通过相同的方法解决:我们定义一个新的“快速子类”标志,表示“此对象是一个描述符,当此对象作为实例的属性查找时,应直接遵循它”。到目前为止,此标志仅在两种类型上设置:propertycollections.abc.InstanceDescriptor。后者是一个抽象基类,其唯一目的是允许用户类继承此“快速子类”标志。

原型

此功能的原型正在 GitHub [github] 上开发。

致谢

Armin Rigo 在遇到“模块属性”的想法时,基本上提出了这个机制,并向作者解释了问题的复杂性和正确的解决方案。Nathaniel J. Smith 指出了 3.5 版本关于将值赋给模块对象上的 __class__ 的扩展,并提供了示例。

参考资料


来源:https://github.com/python/peps/blob/main/peps/pep-0549.rst

最后修改:2025-02-01 08:59:27 GMT