• Day-19 面向对象06 多继承 MRO C3算法 super()(重点)


    一、python多继承

      1.经典类的MRO

    复制代码
    class A:
        pass
    
    class B(A):
        pass
    
    class C(A):
        pass
    
    class D(B, C):
        pass
    
    class E:
        pass
    
    class F(D, E):
        pass
    
    class G(F, D):
        pass
    
    class H:
        pass
    
    class Foo(H, G):
        pass
    复制代码

      对于这样的MRO,画图即可:

      类的MRO:Foo —> H —> G —> F —> E —> D —> B —> A —> C

      2.新式类的MRO

        python中的新式类的MRO是采用的C3算法来完成的

    复制代码
    class A:
        pass
    class B(A):
        pass
    class C(A):
        pass
    class D(B, C):
        pass
    class E(C, A):
        pass
    class F(D, E):
        pass
    class G(E):
        pass
    class H(G, F):
        pass 
    复制代码

      首先. 我们要确定从H开始找. 也就是说. 创建的是H的对象. 
      如果从H找. 那找到H+H的父类的C3, 我们设C3算法是L(x) , 即给出x类. 找到x的MRO
        L(H) = H + L(G) + L(F) +(G,F)
      继续从代码中找G和F的父类往里面带
        L(G) = G + L(E) +(E)
        L(F) = F + L(D)+ L(E) + (D,E)
      继续找E 和 D
        L(E) = E + L(C) + L(A) +(C,A)
        L(D) = D + L(B) + L(C) +(B,C)
      继续找B和C
        L(B) = B + L(A) +(A)
        L(C) = C + L(A) +(A)

      最后就剩下一个A了. 也就不用再找了. 接下来. 把L(A) 往里带. 再推回去. 但要记住. 这里的+ 表示的是merge. merge的原则是用每个元组的头一项和后面元组的除头一项外的其他元素进行比较, 看是否存在. 如果存在. 就从下一个元组的头一项继续找. 如果找不到. 就拿出来.作为merge的结果的一项. 以此类推. 直到元组之间的元素都相同. 也就不用再找了. 

    L(B) =(B,) + (A,) +(A,)-> (B, A)
    L(C) =(C,) + (A,) +(A,)-> (C, A)
    继续带. 
    L(E) = (E,) + (C, A) + (A) + (C,A) -> E, C, A
    L(D) = (D,) + (B, A) + (C, A)  +(B,C)-> D, B, A
    继续带. 
    L(G) = (G,) + (E, C, A) +(E) -> G, E, C, A
    L(F) = (F,) + (D, B, A) + (E, C, A)+ (D,E) -> F, D, B, E, C, A
    加油, 最后了
    L(H) = (H, ) + (G, E, C, A) + ( F, D, B, E, C, A) +(G,F) -> H, G, F, D, B, E, C, A

    算完了. 最终结果 HGFDBECA. 那这个算完了. 如何验证呢? 其实python早就给你准备好
    了. 我们可以使用类名.__mro__获取到类的MRO信息.

    print(H.__mro__)
    结果: 
    (<class '__main__.H'>, <class '__main__.G'>, <class '__main__.F'>, <class
    '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class'__main__.C'>,<class '__main__.A'>, <class 'object'>) 

      这个说完了. 那C3到底怎么看更容易呢? 其实很简单. C3是把我们多个类产生的共同继承留到最后去找. 所以. 我们也可以从图上来看到相关的规律. 这个要大家自己多写多画图就能感觉到了. 但是如果没有所谓的共同继承关系. 那几乎就当成是深度遍历就可以了.

      

    二、super()

      super()可以帮我们执行MRO中下一个父类的方法. 通常super()有两个使用的地方: 

      1. 可以访问父类的构造方法

      2. 当子类方法想调用父类(MRO)中的方法

      第一种:

    复制代码
    class Foo:
        def __init__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c
    
    class Bar(Foo):
        def __init__(self, a, b, c, d):
            super().__init__(a, b, c) # 访问⽗类的构造⽅法
            self.d = d
    
    b = Bar(1, 2, 3, 4)
    print(b.__dict__)
    
    结果: 
    {'a': 1, 'b': 2, 'c': 3, 'd': 4}
    复制代码

      这样就方便了子类. 不需要写那么多了. 直接用父类的构造帮我们完成一部分代码

      第二种:

    复制代码
    class Foo:
        def func1(self):
            super().func1() # 此时找的是MRO顺序中下一个类的func1()方法
            print("我的老家. 就住在这个屯")
    
    class Bar:
        def func1(self):
            print("你的老家. 不在这个屯")
    
    class Ku(Foo, Bar):
        def func1(self):
            super().func1() # 此时super找的是Foo
            print("他的老家. 不知道在哪个屯")
    
    k = Ku() # 先看MRO . KU, FOO, BAR object
    k.func1()
    
    k2 = Foo() # 此时的MRO. Foo object
    k2.func1() # 报错
    复制代码
  • 相关阅读:
    C++输入输出缓冲区的刷新问题
    C++11中新特性之:initializer_list详解
    GCC --verbose选项, -lpthread 和-pthread的区别
    C语言的可变参数
    YCM的安装与配置
    【机器学习】正则化的线性回归 —— 岭回归与Lasso回归
    一文读懂线性回归、岭回归和Lasso回归
    美团酒旅数据治理实践
    kettle完成一个数据库到另一个数据的整体迁移
    kettle完成一个数据库到另一个数据的整体迁移
  • 原文地址:https://www.cnblogs.com/xiaomai-rhce/p/10676098.html
Copyright © 2020-2023  润新知