美文网首页
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