1、了解python2 和python3的区别
python2在2.3之前使用的是经典类,2.3之后,使用的是新式类,新式类的特点是基类的根是object
python3 中使用的都是新式类,如果基类谁都不继承,那么这个类会默认继承object
class Foo: pass class Foo(object): pass
MRO:method resolution order 方法的查找顺序
class Base: pass class Base1: def eat(self): pass class Bar(Base, Base1): pass b = Bar() # Bar --> Base -->Base1 b.eat()
2、经典类的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
画图
结果:Foo-> H -> G -> F -> D -> B -> A -> C -> E.
3、新式类的MRO C3算法
1、拆分
2、合并
用头和身体比较
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找. 那找到H+H的⽗父类的C3, 我们设C3算法是L(x) , 即给出x类. 找到x的MRO
L(H) = H + L(G) + L(F) + GF
继续从代码中找G和F的⽗父类往⾥里里⾯面带
L(G) = G + L(E) + E
L(F) = F + L(D)+ L(E) + DE
继续找E 和 D
L(E) = E + L(C) + L(A) + CA
L(D) = D + L(B) + L(C) + BC
继续找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, C, A
继续带.
L(G) = (G,) + (E, C, A) + (E) -> G, E, C, A
L(F) = (F,) + (D, B, C, 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,
验证
使⽤用类名.__mro__获取到类的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() 找MRO顺序的下一个
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() # 你的老家不在这个屯 # 我的老家就住在这个屯 # 他的老家不知道在哪个屯
5、一道面试题
# MRO + super 面试题 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) c = Add2(2) print(c.val) # Add2 # Mult # 哈哈 # init # 5.0 # 8.0 # Add2 # init # 2 # 4