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

Python 增强提案

PEP 3135 – 新式 super

作者:
Calvin Spealman <ironfroggy at gmail.com>, Tim Delaney <timothy.c.delaney at gmail.com>, Lie Ryan <lie.1296 at gmail.com>
状态:
最终版
类型:
标准跟踪
创建日期:
2007 年 4 月 28 日
Python 版本:
3.0
更新历史:
2007 年 4 月 28 日, 2007 年 4 月 29 日, 2007 年 4 月 29 日, 2007 年 5 月 14 日, 2009 年 3 月 12 日

目录

编号说明

该 PEP 起初是 PEP 367。由于它现在针对 Python 3000,所以它被移动到了 3xxx 命名空间。

摘要

该 PEP 提案为使用 super 类型提供了语法糖,以便自动构造 super 类型实例,并绑定到定义方法的类和正在执行方法的实例(对于类方法,则是类对象)上。

新 super 用法的基本前提如下

super().foo(1, 2)

用于替换旧的

super(Foo, self).foo(1, 2)

基本原理

当前 super 的用法需要显式地传递它必须从中操作的类和实例,这会导致违反 DRY(不要重复自己)原则。这阻碍了任何类名称的更改,并且经常被许多人视为缺点。

规范

在规范部分,将使用一些特殊的术语来区分相似和密切相关的概念。“super 类”将指代名为“super”的实际内置类。一个“super 实例”仅仅是 super 类的实例,它与另一个类和该类的实例(如果有的话)相关联。

新的 super 语义仅在 Python 3.0 中可用。

替换 super 的旧用法,可以调用 MRO(方法解析顺序)中的下一个类,而无需显式传递类对象(尽管这样做仍然受支持)。每个函数都将有一个名为 __class__ 的单元,它包含定义函数的类对象。

新语法

super()

等效于

super(__class__, <firstarg>)

其中 __class__ 是定义方法的类,而 <firstarg> 是方法的第一个参数(对于实例方法通常是 self,对于类方法则是 cls)。对于在类体之外定义的函数,__class__ 未定义,这会导致运行时 SystemError

虽然 super 不是保留字,但解析器在方法定义中识别 super 的使用,并且仅在找到它时才传递 __class__ 单元。因此,调用 super 的全局别名(无参数)不一定有效。

已解决问题

确定要使用的类对象

类对象取自名为 __class__ 的单元。

super 应该真的成为关键字吗?

不。super 不需要成为关键字。

使用 __call__ 属性的 super

有人认为以经典方式实例化 super 实例可能是一个问题,因为调用它将查找 __call__ 属性,因此尝试对 MRO 中的下一个类执行自动 super 查找。但是,事实并非如此,因为调用对象仅直接在对象的类型上查找 __call__ 方法。以下示例显示了它的实际操作。

class A(object):
    def __call__(self):
        return '__call__'
    def __getattribute__(self, attr):
        if attr == '__call__':
            return lambda: '__getattribute__'
a = A()
assert a() == '__call__'
assert a.__call__() == '__getattribute__'

无论如何,这个问题完全消失了,因为仍然支持对 super(<class>, <instance>) 的经典调用,其含义相同。

替代方案

不做改变

尽管保持现状总是很有吸引力,但人们一直都在寻求改变 super 的用法,而且有充分的理由,前面已经提到了所有这些理由。

  • 与类名称解耦(类名称可能不再绑定到正确的类!)
  • 外观更简洁、更干净的 super 调用会更好

super 类型上的动态属性

该提案在 super 类型中添加了动态属性查找,它将自动确定合适的类和实例参数。每次 super 属性查找都会识别这些参数,并在实例上执行 super 查找,就像当前的 super 实现使用对类和实例上的 super 实例的显式调用一样。

该提案依赖于 sys._getframe(),这不适合除原型实现之外的任何用途。

self.__super__.foo(*args)

该 PEP 在多个地方提到了 __super__ 属性,它可能是完整解决方案的候选者,实际上明确使用它而不是直接使用任何 super。但是,双下划线名称通常是内部细节,并且试图将其排除在日常代码之外。

super(self, *args) 或 __super__(self, *args)

该解决方案仅解决了类型指示的问题,没有处理不同命名的 super 方法,并且明确说明了实例的名称。它不太灵活,因为它无法在其他方法名称上执行,而这在需要的时候非常有用。该方案失败的一个用例是,当基类有一个工厂类方法,子类有两个工厂类方法时,两者都需要对基类中的工厂类方法进行适当的 super 调用。

super.foo(self, *args)

这种变体实际上消除了定位正确实例的问题,如果任何替代方案被推到聚光灯下,我希望是这个方案。

super(*p, **kw)

有人提议直接调用 super(*p, **kw) 等效于在名为与当前正在执行的方法相同的名称的 super 对象上调用该方法,即以下两种方法等效

def f(self, *p, **kw):
    super.f(*p, **kw)
def f(self, *p, **kw):
    super(*p, **kw)

对此有强烈的支持和反对意见,但实施和风格问题是显而易见的。Guido 建议根据 KISS(保持简单原则)将此排除在该 PEP 之外。

历史

2007 年 4 月 29 日
  • 将标题从“Super 作为关键字”更改为“新式 super”
  • 更新了大部分语言,并添加了一个术语部分,以便在令人困惑的地方进行澄清。
  • 添加了参考实现和历史部分。
2007 年 5 月 6 日
  • 由 Tim Delaney 更新,以反映在 python-3000 和 python-dev 邮件列表上的讨论。
2009 年 3 月 12 日
  • 更新为反映当前的实现状态。

参考

[1] 修复 super,有人吗? (https://mail.python.org/pipermail/python-3000/2007-April/006667.html)

[2] PEP 3130:访问正在定义的模块/类/函数(此文档) (https://mail.python.org/pipermail/python-ideas/2007-April/000542.html)


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

最后修改时间:GMT 2023 年 9 月 9 日 17:39:29