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

问题描述

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()

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

解决方法

documentationsuper()的工作方式有很好的解释:

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

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

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

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

super()等效于表达式super(__class__,self),其中__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方法的搜索从child1序列中MRO 之后的类,并且具有form1方法的第一个匹配类是child2

之所以发生这种情况,是因为您使用的是钻石继承结构以及MRO的principles

具有多个继承层次结构,线性化的构建比较麻烦,因为要构建尊重本地优先级排序单调性的线性化更加困难。 >

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