C3算法 和 super
一. Python的继承 多继承
子类继承父类.
继承是为了节省开发时间.提高开发效率 代码得到了重(chong)用 一个类可以拥有多个父类
lass shen_xian: # 定义一个神仙类 def fei(self): # 神仙类有一个方法 可以飞 print('神仙都会飞') class Monkey: # 定义一个猴子类 def chitao(self): # 猴子有一个方法 可以吃桃子 print('猴子喜欢吃桃') class SunWuKong(Monkey,shen_xian): # 对象继承猴子和神仙的类型 pass sxz = SunWuKong() # 实例化一个孙悟空对象 sxz.chitao() # 会吃桃子 sxz.fei() # 会飞
多继承用起来简单 但是存在一个问题 当父类中出现重名方法时 就涉及到查找父类方法中的问题 也即MRO(method resolution order)
二. 经典类的MRO
在Python2中存在两种类
经典类 : 在Python 2.2 之前 一直使用的是 经典类
新式类 : 在2.2之后 出现了新式类 特点是 基类的根是object
Python 3
只有新式类 如果基类谁都不继承 那么会默认继承object
经典类的MRO 深度优先遍历 例如 快递员送鸡蛋 :
肯定是按照123456顺序来送 即每次都是最左边 找完撤回到分叉口继续往里找(从左往右,一条道跑到黑,然后撤回继续一条道跑到黑) 即深度优先遍历 如果 142356 就是广度优先遍历
三. 新式类的MRO, C3(重点, 难点) 可以通过 类名.__mro__ 获取到类的mro信息
即print(类名.__mro__) 就可以获取到
Python中的新式类的mro都是用 c3算法来完成的
笔试的时候肯定会考
新式类中摒弃了(部分). C3算法
如果继承关系没有菱形继承(深度优先)
如果有菱形:使用C3算法来计算MRO
三. 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()方法 实际到这就会报错 根本不会运行 # 因为 Foo 中没有func1方法 继承的obj中也没有func1()方法 print('我的老家,就住在这个屯') class Bar: def func(self): print('你的老家,不在这个屯') class Ku(Foo,Bar): def func1(self): super().func1() print('它的老家,不知道在哪个屯') k = Ku() # 先看mro Ku , Foo, Bar ,object k.func1() k2 = Foo() # 此时的mro Foo , object 都没有func1 因此会报错 如果这样写一开始就会报错 就不会运行到这才报错 k2.func1()
五. 一道面试题
# mro + super 面试题 class Init: 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 p = Incr(5) print(p.val) c = Add2(2) print(c.val)
结论 : 不管super()写在哪. 在哪执行,一定先找到mro列表.根据mro列表的顺序往下找 否则都是错的.