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().foo(1, 2)

取代旧的

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

基本原理

super 的当前用法要求显式传递它必须操作的类和实例,这违反了 DRY(Don’t Repeat Yourself)规则。这阻碍了类名称的任何更改,并且经常被许多人认为是缺陷。

规范

在规范部分,将使用一些特殊术语来区分相似和密切相关的概念。“super class”将指实际的内置类“super”。“super instance”只是 super class 的一个实例,它与另一个类相关联,并且可能与该类的一个实例相关联。

新的 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 实例所做的那样。

此提案依赖于 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(Keep It Simple Stupid)原则将其排除在本 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

最后修改时间: 2025-02-01 08:55:40 GMT