Python中的"super"如何做到正确的事情?

29 浏览
0 Comments

Python中的"super"如何做到正确的事情?

我正在使用 Python 2.5,因此这个问题可能不适用于 Python 3。当您使用多重继承创建一个菱形类层次结构并创建派生最多的类的对象时,Python 会做正确的事情(TM)。它按从左到右列出的父类的顺序调用派生的构造函数,然后是父类,最后是祖先。我熟悉 Python 的MRO,这不是我的问题。我想知道从 super 返回的实际对象如何成功地与父类中的 super 调用通信以获取正确的顺序。考虑下面的示例代码:

#!/usr/bin/python
class A(object):
    def __init__(self): print "A init"
class B(A):
    def __init__(self):
        print "B init"
        super(B, self).__init__()
class C(A):
    def __init__(self):
        print "C init"
        super(C, self).__init__()
class D(B, C):
    def __init__(self):
        print "D init"
        super(D, self).__init__()
x = D()

代码做出了直观的事情,它打印出:

D init
B init
C init
A init

然而,如果你注释掉 B 的 init 函数中的 super 调用,则不会调用 A 或 C 的 init 函数。这意味着 B 的 super 调用以某种方式意识到 C 在整个类层次结构中的存在。我知道 super 返回一个代理对象,它具有重载的 get 操作符,但是在 D 的 init 定义中返回的对象如何通知在 B 的 init 定义中返回的对象以存在 C?后续的 super 调用使用的信息是否存储在对象本身上?如果是这样,为什么不是 self.super 而是 super ?

编辑:Jekke 正确指出 super 不是 self.super,因为 super 是类的属性,而不是类的实例。这在概念上是有道理的,但实际上 super 也不是类的属性!您可以在解释器中制作两个类 A 和 B,其中 B 继承自 A,并调用 dir(B)。它没有 super 或 __super__ 属性。

admin 更改状态以发布 2023年5月20日
0
0 Comments

我在下面提供了一堆链接,它们比我所能做到的更详细,更精确地回答了你的问题。然而我也会用我的自己的话回答你的问题,以便为你节约时间。以下是我的回答:

  1. super是一个内置函数,而不是一个属性。
  2. Python中的每个类型(类)都有一个__mro__属性,它存储了该特定实例的方法调用顺序。
  3. 每次super的调用形式都是super(type[, object-or-type])。现在我们假设第二个属性暂时是一个对象。
  4. super调用的起点,对象是派生类的类型(假设为DC)。
  5. super在MRO中查找匹配(在您的情况下是__init__)的方法,这些方法在第一个参数指定的类之后的类中找到(在这种情况下是DC之后的类)。
  6. 当找到匹配方法时(假设在BC1类中),它被调用。
    (这个方法应该使用super,所以我假设这样做了 - 请参见下面的Python的super非常棒,但不能使用 - 链接)
  7. 然后,该方法会导致在对象的类的MRO中搜索下一个方法,位于BC1右侧。
  8. 重复上述过程直到找到并调用所有方法。

针对您的示例的解释

 MRO: D,B,C,A,object  

  1. super(D, self).__init__()被调用。isinstance(self, D) => True
  2. 在MRO中搜索在D右侧的类中的下一个方法

    找到并调用B.__init__


  1. B.__init__调用super(B, self).__init__()

    isinstance(self, B) => False
    isinstance(self, D) => True

  2. 因此,MRO相同,但搜索继续到B的右边,即逐一搜索C、A、object。找到下一个__init__并调用它。

  3. 以此类推。

super的解释
http://www.python.org/download/releases/2.2.3/descrintro/#cooperation
使用super时要注意的事项
http://fuhm.net/super-harmful/
Python的MRO算法:
http://www.python.org/download/releases/2.3/mro/
super的文档:
http://docs.python.org/library/functions.html
本页底部有一个有关super的不错的部分:
http://docstore.mik.ua/orelly/other/python/0596001886_pythonian-chp-5-sect-2.html

希望这有所帮助,澄清了问题。

0
0 Comments

将你的代码更改为以下内容,我认为它可以解释一些事情(很可能是super正在查看__mro__B所处的位置 ?):

class A(object):
    def __init__(self):
        print "A init"
        print self.__class__.__mro__
class B(A):
    def __init__(self):
        print "B init"
        print self.__class__.__mro__
        super(B, self).__init__()
class C(A):
    def __init__(self):
        print "C init"
        print self.__class__.__mro__
        super(C, self).__init__()
class D(B, C):
    def __init__(self):
        print "D init"
        print self.__class__.__mro__
        super(D, self).__init__()
x = D()

如果你运行它,你会看到:

D init
(, , , , )
B init
(, , , , )
C init
(, , , , )
A init
(, , , , )

另外,值得一提的是,要查看Python的超级(Super)很棒,但你不能使用它

0