方法解析顺序 (MRO) 在此 Python 代码中如何工作

Stu*_*Man 5 python oop multiple-inheritance super

class parent:
    def __init__(self):
        self.a=2
        self.b=4
    def form1(self): 
        print("calling parent from1")
        print('p',self.a+self.b)
 
class child1(parent):
    def __init__(self):
        self.a=50
        self.b=4
    def form1(self):
        print('bye',self.a-self.b)
    def callchildform1(self):
        print("calling parent from child1")
        super().form1()
 
class child2(parent):
    def __init__(self):
        self.a=3
        self.b=4
    def form1(self):
        print('hi',self.a*self.b)
    def callchildform1(self):
        print("calling parent from child2")
        super().form1()
 
class grandchild(child1,child2):
    def __init__(self):
        self.a=10
        self.b=4
    def callingparent(self):
        super().form1()
 
g=grandchild()
g.callchildform1()
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,当我调用 时g.callchildform1(),根据 MRO 规则,将首先在同一个类中搜索该方法,然后是第一个父级(此处为 child1),然后是第二个父级(child2)。正如预期的那样,它调用child1.callchildform1()并执行第一行print("calling parent from child1")super().form1()但在此之后,我预计将执行下一行,该行将被调用parent.form1(),但这种情况不会发生。相反,child2.form1()正在被调用。请解释一下为什么会出现这种情况?

ale*_*ame 4

文档对如何工作有很好的解释super()

super([type[, object-or-type]])

返回一个代理对象,该对象将方法调用委托给该类型的父类或同级类。这对于访问类中已重写的继承方法很有用。

确定要搜索的object-or-type方法解析顺序。搜索从类型之后的类开始。

例如,如果__mro__ofobject-or-typeD -> B -> C -> A -> object并且 type 的值为B,则super()搜索C -> A -> object

super()等价于表达式super(__class__, self)where__class__是一个类对象,在该类对象的方法中super()调用了 。例如,super()本质上grandchild.callingparent(self)super(grandchild, self)。内部super()函数child1.callchildform1(self)super(child1, self).

MRO对于grandchild(<grandchild>, <child1>, <child2>, <parent>, <object>). 因此,根据上述文档摘录,当super().form1()在 中调用时child1.callchildform1(),相当于,从序列中紧随其后的类开始super(child1, self)搜索方法form1,并且第一个与方法匹配的类是。child1MROform1child2

发生这种情况是因为您正在使用钻石继承结构和MRO 的基础原则:

对于多重继承层次结构,线性化的构造更加麻烦,因为构造尊重局部优先顺序单调性的线性化更加困难。

在设计这样的层次结构时,需要遵循合作继承的方法,可以在这篇已经很经典的文章中找到解释。