zoukankan      html  css  js  c++  java
  • day28 Pyhton MRO和C3算法

    1.python多继承.一个类可以拥有多个父类

    class ShenXian: # 神仙
        def fei(self):
            print("神仙都会飞")
    class Monkey: #
        def chitao(self):
            print("猴子喜欢吃桃子")
    class SunWukong(ShenXian, Monkey): # 孙悟空是神仙, 同时也是一只猴
        pass
    sxz = SunWukong() # 孙悟空
    sxz.chitao() # 会吃桃子
    sxz.fei() # 会飞
    此时, 孙悟空是一只猴子, 同时也是一个神仙. 那孙悟空继承了了这两个类. 孙悟空自然就可以执行行这两个类中的方法.
    多继承用起来简单. 也很好理理解. 但是多继承中, 存在着这样一个问题. 当两个父类中出现了了重名方法的时候. 这时该怎么办呢? 这时就涉及到如何查找父类方法的这么一个问题.
    即MRO(method resolution order) 问题. 在python中这是一个很复杂的问题. 因为在不同的python版本中使用的是不同的算法来完成MRO的. 首先. 我们目前能见到的有两个版本:
    python2
    在python2中存在两种类.
    一个叫经典类. 在python2.2之前. 一直使用的是经典类. 经典类在基类的根如
    果什什么都不写. 表示继承xxx.
    一个叫新式类. 在python2.2之后出现了了新式类. 新式类的特点是基类的根是
    object
    python3
    python3中使用的都是新式类. 如果基类谁都不继承. 那这个类会默认继承object

    2.经典类的MRO

    记住一个原则. 在经典类中采用的是深度优先
     什什么是深度优先. 就是一条路路走到头. 然后再回来继续找下一个

    3.新式类的MRO

    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的父类往里面带
    L(G) = G + L(E)
    L(F) = F + L(D)+ L(E)
    继续找E 和 D
    L(E) = E + L(C) + L(A)
    L(D) = D + L(B) + L(C)
    继续找B和C
    L(B) = B + L(A)
    L(C) = C + L(A)
    最后就剩下一个A了了. 也就不用再找了了. 接下来. 把L(A) 往里带. 再推回去. 但要记住. 这里的
    + 表示的是merge. merge的原则是用每个元组的头一项和后面元组的除头一项外的其他元
    素进行比较, 看是否存在. 如果存在. 就从下一个元组的头一项继续找. 如果找不到. 就拿出来.
    作为merge的结果的一项. 以此类推. 直到元组之间的元素都相同. 也就不用再找了了.
    L(B) =(B,) + (A,) -> (B, A)
    L(C) =(C,) + (A,) -> (C, A)
    继续带.
    L(E) = (E,) + (C, A) + (A) -> E, C, A
    L(D) = (D,) + (B, A) + (C, A) -> D, B, A
    继续带.
    L(G) = (G,) + (E, C, A) -> G, E, C, A
    L(F) = (F,) + (D, B, A) + (E, C, A) -> F, D, B, E, C, A
    加油, 最后了了
    L(H) = (H, ) + (G, E, C, A) + ( F, D, B, E, C, A) -> 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是把我们多个类产生的共同继承留留到最后去找. 所以. 我们也可以从图上来看到相关的规律律. 这个要大家自己多写多画图就

    能感觉到了了. 但是如果没有所谓的共同继承关系. 那几乎就当成是深度遍历就可以了.

    4.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() # 报错
    class Init(object):
        def __init__(self, v):
            print("init")
            self.val = v
    class Add2(Init):
        def __init__(self, val):
            print("Add2")
            super(Add2, self).__init__(val)
            print(self.val)
            self.val += 2
    class Mult(Init):
        def __init__(self, val):
            print("Mult")
            super(Mult, self).__init__(val)
            self.val *= 5
    class HaHa(Init):
        def __init__(self, val):
            print("哈哈")
            super(HaHa, self).__init__(val)
            self.val /= 5
    class Pro(Add2,Mult,HaHa): #
        pass
    class Incr(Pro):
        def __init__(self, val):
            super(Incr, self).__init__(val)
            self.val+= 1
    # Incr Pro Add2 Mult HaHa Init
    # p = Incr(5)
    # print(p.val)
    #Add2
    #Mult
    #哈哈
    #init
    #5.0
    #8.0
    # c = Add2(2)
    # print(c.val)
    #Add2
    #init
    #2
    #4
  • 相关阅读:
    2014 中华架构师大会 回想
    mybatis重拾---部署官方demo
    D 语言学习感受
    D语言学习
    D语言简介
    C++输入cin详解
    C++源文件的后缀名问题
    C 函数指针详解
    Linux下的五个查找命令:grep、find、locate、whereis、which
    Qt---QFtp上传、下载二进制文件
  • 原文地址:https://www.cnblogs.com/pythonz/p/9993743.html
Copyright © 2011-2022 走看看