为什么python的super不只接受实例?

5 投票
2 回答
662 浏览
提问于 2025-04-15 17:20

在 Python 2.x 中,super 有以下几种用法:

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:

据我所知,super 是一个类,它把类型和(最终)实例包裹起来,以便找到一个类的父类。

我有几个地方感到困惑:

  • 为什么没有 super(instance) 这种用法?通常我们会用 super(self).__init__()。从技术上讲,你可以通过对象本身获取它的类型,所以现在的用法 super(ClassType, self).__init__() 有点多余。我猜这可能是为了兼容旧式类或者处理多重继承,但我想听听你的看法。
  • 另一方面,为什么 Python 3 会接受 super().__init__() 这种写法?我觉得这有点神奇,似乎违背了“显式优于隐式”的原则。我觉得用 self.super().__init__() 会更合适。

2 个回答

3

我不能给出具体的答案,但你有没有看过关于super关键字的PEP文档?我快速搜索了一下,找到了PEP 367和PEP 3135。

http://www.python.org/dev/peps/pep-0367/

http://www.python.org/dev/peps/pep-3135/#numbering-note

与我知道的其他语言不同的是,通常你可以在PEP文档中找到Python的一些特殊用法的答案,还有清晰的解释和立场说明。

更新:

看完了3135和相关的Python邮件列表以及语言参考文档后,我大致明白了为什么Python 2和Python 3在这方面的不同。

http://docs.python.org/library/functions.html?highlight=super#super

我觉得super这个功能的设计是为了让事情变得明确和冗余,这样可以更安全,并且保持逻辑尽可能简单(没有复杂的逻辑去寻找父类)。因为super是一个内置函数,它必须根据提供的信息推断出正确的返回值,而不增加Python对象结构的复杂性。

PEP 3135改变了一切,因为它提出并赢得了一个关于让super更简洁的论点。

6

super(ClassType, self).__init__() 在多重继承的情况下并不是多余的——ClassType 不一定是 self 的类型,而是你想要调用的那个类的名字,用来进行合作调用 __init__ 方法。

在类的继承关系中,比如 C 继承 B 继承 A,在 C.__init__ 中,你想从 C 的角度调用父类的初始化方法,所以你会调用 B.__init__;然后在 B.__init__ 中,你必须把类类型 B 传给 super——因为你想要解决 B 的父类调用(或者说,C 的方法解析顺序中 B 之后的下一个类)。

class A (object):
  def __init__(self):
    pass

class B (A):
  def __init__(self):
    super(B, self).__init__()

class C (B):
  def __init__(self):
    super(C, self).__init__()

如果你现在创建一个实例 c = C(),你会发现类类型并不是多余的——在 B.__init__ 中使用 super(self).__init__() 实际上是行不通的!你需要手动指定调用 super 的方法所在的类(在 Python 3 中,这个问题通过一个指向方法所在类的隐藏变量来解决)。

这里有两个关于 super 和多重继承的示例链接:

撰写回答