如何从父 类 调用 "overriden" 方法?

How to call "overriden" methods from both parent classes?

考虑以下 类,其中 P1P2C 的父级 类:

class P1:
    def f(self):
        print('P1')


class P2:
    def f(self):
        print('P2')


class C(P1, P2):
    def f(self):
        print('C')
        # super().f()
        # super(P1, self).f()

c = C()
c.f()

当我运行这个时,它打印C

如果我取消注释第一行 super().f(),那么它也会打印 P1
因为 super() 将从直接父级调用方法,P1

如果我取消注释第二行 super(P1, self).f(),那么它也会打印 P2 因为 super(P1, self) 会调用 P1 的兄弟 P2

的方法

我想知道的是,如果有任何方法可以通过一次调用从父 类 P1P2 调用 f 方法super() 函数,而不是像我那样调用它两次。

或者,有没有其他方法可以在不使用 super 函数的情况下做到这一点?

没有什么好的方法可以完全按照您的意愿行事。但是如果可以同时修改P1P2,就可以实现协同多重继承,只需要在父class的两个父class中添加一个baseclass即可该方法的无操作实现:

class GP: # grandparent base class
    def f(self):
        pass  # do nothing

class P1(GP):
    def f(self):
        print("P1")
        super().f()

class P2(GP):
    def f(self):
        print("P2")
        super().f()

class C(P1, P2):
    def f(self):
        print("C")
        super().f()

之所以有效,是因为 super 并不完全意味着 "my parent class"。意思是"next in the MRO' for this object"。 MRO 是方法解析顺序,基本上是在继承中搜索事物的顺序。当在C中调用super()时,它会找到P1中的方法。但是当在 P1 中调用 super() 时(在 C 的实例上),它调用 P2,因为 C 实例的 MRO 是 [C, P1, P2, GP, object]. P2 出现在 P1 之后,因此它被第二个 super 调用选中。

需要 GP class 来结束 super 调用链。如果您没有它,最后的 super 调用将解析为 object(这是所有继承树的根)并且由于没有这样的方法,您会得到一个错误。基础class中的实现不需要什么都不做,只需要最后不调用super即可。

Super从派生的方法解析顺序(MRO)调用下一个方法class.

方法f的每一个实现都应该调用super,parent classes之间不需要相互了解,super会自动调用MRO中的next方法

编辑:我忘记了 mro 中的最后一个 class 总是 object。 object 没有名为 f 的方法。所以你应该注意 mro 中最后一个 class 有那个方法,要么不调用 super().f 要么捕获 AttributeError.

只要遵循C3线性化规则,childclass就可以改MRO。这意味着派生的 class 决定了哪些代码获得 运行 以及哪些代码没有获得 运行。这是依赖注入的一种方式。

您可以通过 __mro__ 属性检查 class 的 MRO。

此答案主要基于 Raymond Hettinger

的演讲 super considered super
class P1:
    def f(self):
        super().f()
        print('P1')

class P2:
    def f(self):
        print('P2')

class C(P1, P2):
    def f(self):
        super().f()
        print('C')

class C2(P2, P1):
    def f(self):
        super().f()
        print('C2')

>>> C().f()
P2
P1
C
>>> C2().f()
P2
C2
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.P1'>, <class '__main__.P2'>, <type 'object'>)
>>> C2.__mro__
(<class '__main__.C2'>, <class '__main__.P2'>, <class '__main__.P1'>, <type 'object'>)