方法解析顺序 (MRO) 如何在此 Python 代码中工作 [英] How Method Resolution Order (MRO) is working in this Python code

查看:52
本文介绍了方法解析顺序 (MRO) 如何在此 Python 代码中工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 类父级:def __init__(self):self.a=2self.b=4def form1(self):打印(从 1 调用父级")打印('p',self.a+self.b)班级 child1(父母):def __init__(self):self.a=50self.b=4def form1(self):打印('再见',self.a-self.b)def callchildform1(self):打印(从 child1 调用父级")超级().form1()班级 child2(父母):def __init__(self):self.a=3self.b=4def form1(self):打印('嗨',self.a*self.b)def callchildform1(self):打印(从 child2 调用父级")超级().form1()孙子类(child1,child2):def __init__(self):self.a=10self.b=4def callparent(self):超级().form1()g=孙子()g.callchildform1()

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

解决方案

文档很好地解释了 super() 的工作原理:

<块引用>

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

返回一个代理对象,该对象将方法调用委托给类型的父类或兄弟类.这对于访问在类中被覆盖的继承方法很有用.

object-or-type 决定了要搜索的方法解析顺序.搜索从紧接着类型的类开始.

<块引用>

例如,如果 object-or-type__mro__D ->B->C->->object,type的值为B,然后super()搜索C ->->对象.

super() 等价于表达式 super(__class__, self) 其中 __class__ 是一个类对象,其方法中的 super() 被调用.例如,grandchild.callingparent(self) 中的 super() 本质上就是 super(grandchild, self).而child1.callchildform1(self)函数里面的super()就是super(child1, self).

MRO for grandchild().因此,根据以上文档摘录,当在child1.callchildform1()中调用super().form1()时,相当于super(child1, self)form1 方法的搜索MRO中child1之后的类开始 序列,第一个与 form1 方法匹配的类是 child2.

出现这种情况是因为您使用的是菱形继承结构和原则 是 MRO 的基础:

<块引用>

对于多重继承层次结构,线性化的构建更加繁琐,因为更难构建符合局部优先顺序单调性的线性化.>

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

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

In the above code, when I call g.callchildform1(), according to MRO rule, the method will be first searched in the same class, then the first parent (child1 here) and then the second parent (child2). As expected, it calls child1.callchildform1() and executes the first line print("calling parent from child1"). But after this, I expected that the next line super().form1() will be executed which will call parent.form1() but this doesnt happen. Instead, child2.form1() is being called. Please explain why this happens?

解决方案

The documentation has a great explanation of how super() works:

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

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class.

The object-or-type determines the method resolution order to be searched. The search starts from the class right after the type.

For example, if __mro__ of object-or-type is D -> B -> C -> A -> object and the value of type is B, then super() searches C -> A -> object.

super() is equivalent to the expression super(__class__, self) where __class__ is an class object within whose method the super() is called. For example, super() within grandchild.callingparent(self) is essentially super(grandchild, self). And super() inside child1.callchildform1(self) function is super(child1, self).

MRO for grandchild is (<grandchild>, <child1>, <child2>, <parent>, <object>). Therefore, according to the above excerpt from documentation, when super().form1() is called in child1.callchildform1(), which is equivalent to super(child1, self), the search for the form1 method starts from the class right after the child1 in the MRO sequence and the first matching class with form1 method is child2.

This occurs due to that you are using the diamond inheritance structure and the principles that underlie the MRO:

with multiple inheritance hierarchies, the construction of the linearization is more cumbersome, since it is more difficult to construct a linearization that respects local precedence ordering and monotonicity.

When designing such hierarchies, it is need to follow the approach of cooperative inheritance, an explanation can be found, in this already classic article.

这篇关于方法解析顺序 (MRO) 如何在此 Python 代码中工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆