美文网首页
Python的MRO查找

Python的MRO查找

作者: 李白开水 | 来源:发表于2020-07-17 17:20 被阅读0次

MRO:Method Resolution Order
类的属性和实例的属性的关系:
如果现在有一个类A,他有一个属性name:

image.png
现在把他实例化:
image.png
打印这个实例的name:
image.png
现在用__init__初始化实例的变量:
image.png
再打印实例a的属性name:
image.png
name的查找顺序是由下至上的,先查找实例的属性name,如果找不到,再查找类的属性name。

在多继承的情况下,这个顺序就会变得复杂。
如果基础关系是这样的:

image.png
那么如果搜索顺序是先搜索B——>D——>C——>E那么会出现一个问题就是:
如果D和C有重名的方法,如果按照这个顺序搜索,C中的方法可能永远也使用不到。
可以通过一种方法来查看实际的运行顺序是__mro__:
image.png
python3后如果类不继承任何类,那么它默认继承object类。

如果基础关系是这样的:
那么如果搜索顺序是先搜索B——>D——>C那么会出现一个问题就是:
如果C中重写了D的方法,如果按照这个顺序搜索,C中的方法也可能永远也使用不到。

image.png
查看实际的运行顺序__mro__:
image.png

从python2.3之后,python的属性搜索算法统一为一个算法叫C3算法,C3算法保证了以后每一个父类只会被调用一次。
具体实现见维基百科:
https://zh.wikipedia.org/wiki/C3%E7%BA%BF%E6%80%A7%E5%8C%96

所以如果现在有一个Parent类,一个Son1类继承自Parent,一个Son2类继承自Parent,再有一个Grandson继承自Son1和Son2,,如果想要不重复调用Parent中的方法,可以用super()

class Parent(object):
    def __init__(self, name, *args, **kwargs):
        print('Parent1')
        self.name = name
        print('Parent2')

class Son1(Parent):
    def  __init__(self, name, age,*args, **kwargs):
        print("***Son1***")
        self.age = age
        super().__init__(name, *args, **kwargs)
        print("***Son1***")

class Son2(Parent):
    def  __init__(self, name, gender,*args, **kwargs):
        print("***Son2***")
        self.gender = gender
        super().__init__(name, *args, **kwargs)
        print("***Son2***")

class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print("Grandson")
        super().__init__(name, age, gender)
        print("Grandson")

print(Grandson.__mro__  )

运行程序:

D:\>python test08.py
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)

这个打印的结果就是C3算法的结果,它表示这个Grandson调用父类方法的顺序,也就是super到__mro__里面去匹配,匹配到当前的类名,然后调用它的下一个类里的方法。
如果当前把Grandson实例化,可以看到打印顺序:

g1 = Grandson("haha", 12, "male")

运行:

(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson
***Son1***
***Son2***
Parent1
Parent2
***Son2***
***Son1***
Grandson

super还有参数可以传递:

super(Grandson, self).__init__(name, age, gender)

当没有参数的时候,默认去mro中匹配的是当前的类名,有参数就去匹配给定的参数。
如果当前Grandson中的super传递参数如下:

super(Grandson, self).__init__(name, age, gender)

运行结果:

D:\>python test08.py
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson
***Son1***
***Son2***
Parent1
Parent2
***Son2***
***Son1***
Grandson

如果当前Grandson中的super传递参数如下:

super(Son2, self).__init__(name, age, gender)

运行结果:

D:\>python test08.py
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson
Parent1
Parent2
Grandson

而此时传递的参数就要注意了,父类需要的参数要传递过去。

相关文章

网友评论

      本文标题:Python的MRO查找

      本文链接:https://www.haomeiwen.com/subject/kjtnhktx.html