一:python多继承
python多继承中,当一个类继承了多个父类时候,这个类拥有多个父类的所欲非私有的属性
l例子:
class A:
pass
class B(A):
pass
class C(A,B):
pass
B继承了A的属性,C继承了A和B的属性
二:多继承中出现的问题:
问题一:当一个类继承了多个父类,而这几个父类里面的方法名字写的一样,那该怎么办呢?
例如:
class A:
def login(self):
pass
class B(A):
def login(self):
pass
class C(A,B):
def a(self):
pass
这种情况下怎么去找呢? 这就涉及到了怎么查找父类的方法:
MRO(method resolution order) 方法
有两个查找版本:一个是python 2.2版本的经典类, 一个是python3版本后的C3算法
经典版本MRO的查找原则,从左到右,先把左边的一条路找完,再回来继续找下一个(一条路走到黑)
新式的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的父类往里面带
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. 我们也可以用 类名.__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'>)
总结:通过一层一层的先拆分,将原来的程序中的类按照它给的继承关系,列出如上诉的
继承关系公式,然后再 用前一个的类(集合)的头和后面一个方法的 尾部(除去第一个类的后面、的类)
对比,如果前面这个头的类名出现在了后面,那么这个头部的类名就去掉,继续这个类集合的下一个,如此循环
直到找完就,最终得到一个 # L(H) = (H,) + (G, E, C, A) + (F, D, B, E, C, A) -> H, G, F, D, B, E, C, A
这样的表达式,这就算是找完了。
解释:C3算法: C3是把我们多个类产⽣的共同继承留到最后去找. 所以. 我们也可以从图上来看到相关
的规律. 这个要⼤家⾃⼰多写多画图就能感觉到了. 但是如果没有所谓的共同继承关系. 那⼏乎就当成
是深度遍历就可以了
三:super() 函数:
super()是查找mro顺序的下一个:单继承中我们可以认为super是对父类中的属性或则方法的引入
class ShengWu:
def dong(self):
print(self)
print("生物")
class Animal(ShengWu):
pass
class Cat(Animal):
def dong(self): #子类中出现了和父类重名的内容,表示父类的方法的覆盖
super().dong() #定位到Animal 找Animal的下一个
#super(类,对象).方法() 找到MRO中的类,找这个类的下一个,去执行方法
print("猫会动")
#找MRO中的下一个
#Cat-->Animal--> ShengWu
c=Cat()
print(c)
c.dong()
例子
MRO+super面试题
class Init(object):
def __init__(self, v):
print("init")
self.val = v # 2
class Add2(Init):
def __init__(self, val): # 2
print("Add2")
super(Add2, self).__init__(val)
print(self.val) # 5.0
self.val += 2 # 7.0
class Mult(Init):
def __init__(self, val):
print("Mult")
super(Mult, self).__init__(val)
self.val *= 5 # 5.0
class HaHa(Init):
def __init__(self, val):
print("哈哈")
super(HaHa, self).__init__(val)
self.val /= 5 # 1.0
class Pro(Add2,Mult,HaHa): #
pass
class Incr(Pro):
def __init__(self, val): # 5
super(Incr, self).__init__(val)
self.val += 1 # 8.0
p = Incr(5)
print(p.val)
# Add2 init
c = Add2(2)
print(c.val)
MRO算法后的顺序是(计算print(p.val)--> # Incr, pro, add2, mult, haha, Init(可以用print(Incr.__mro__)验证)
print(p.val) 打印结果是: add2 Mult 哈哈 init 5.0 8.0
print(c.val) 打印结果: Add2 init 2 4