MRO在多重继承时的作用

2021年2月15日 / 31次阅读 / Last Modified 2021年2月15日
面向对象

MRO,Method Resolution Order,应该是一个比较通用的概念,具体是指在有继承关系,特别是多重继承关系的OOP代码中,子类的对象在调用继承下来的函数时,要通过MRO的顺序,去定位具体的调用位置。

class aa:
    def __init__(self):
        print('in aa')

    def fun(self):
        print('in aa fun')


class bb:
    def __init__(self):
        print('in bb')

    def fun(self):
        print('in bb fun')


class cc(aa,bb):
    pass
        


c = cc()
c.fun()
print(cc.mro())

cc继承aa和bb,因此cc的__init__和fun函数,都需要MRO来决策具体的调用位置,因为这两个函数,在aa和bb中都存在。这段代码的运行效果如下:

in aa
in aa fun
[<class '__main__.cc'>, <class '__main__.aa'>, <class '__main__.bb'>, <class 'object'>]

按照MRO的顺序,cc的两次调用,都定位在aa内。

cc.mro()输出类cc的MRO顺序list!MRO顺序,就是代码中的书写顺序,aa写在bb前面,MRO中,aa就在bb前面!

与MRO密切相关的,是一个我们常见的super函数。

下面这段代码描述的继承关系,存在重复调用:

class aa:
    def __init__(self):
        print('in aa')


class bb(aa):
    def __init__(self):
        print('in bb')
        aa.__init__(self)


class cc(aa):
    def __init__(self):
        print('in cc')
        aa.__init__(self)


class dd(bb,cc):
    def __init__(self):
        print('in dd')
        bb.__init__(self)
        cc.__init__(self)
        

dd()

这段代码运行的效果:

in dd
in bb
in aa
in cc
in aa

可以看到in aa出现了两次,有重复调用。

这种场景下,使用super函数,就可以避免重复调用:

class aa:
    def __init__(self):
        print('in aa')


class bb(aa):
    def __init__(self):
        print('in bb')
        super(bb, self).__init__()


class cc(aa):
    def __init__(self):
        print('in cc')
        super(cc, self).__init__()


class dd(bb,cc):
    def __init__(self):
        print('in dd')
        super(dd, self).__init__()
        

dd()
print(dd.mro())
print(cc.mro())

运行效果:

in dd
in bb
in cc
in aa
[<class '__main__.dd'>, <class '__main__.bb'>, <class '__main__.cc'>, , <class 'object'>]
[<class '__main__.cc'>, <class '__main__.aa'>, <class 'object'>]

super函数内有两个参数,第1个参数是类,表示在MRO顺序中,查找这个类的下一个类。上面的代码,如果在bb的__init__中,代码改写成super(cc,self)......就是一个无限递归循环,直到maximum。super函数的那两个参数,可以不写。

以后看到super,就要想到MRO,就搞定了。

MRO满足两个性质:(1)本地优先;(2)单调性;

本地优先:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。
单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。

Python用一个叫C3的算法来生成MRO。

-- EOF --

本文链接:https://www.pynote.net/archives/3500

留言区

《MRO在多重继承时的作用》有1条留言

您的电子邮箱地址不会被公开。 必填项已用*标注

  • 麦新杰

    一句话,用super更安全,一般不用提供参数。 [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top