继承实现的原理
一继承顺序
在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)
如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性
如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class A(object): 2 def test(self): 3 print('from A') 4 5 class B(A): 6 def test(self): 7 print('from B') 8 9 class C(A): 10 def test(self): 11 print('from C') 12 13 class D(B): 14 def test(self): 15 print('from D') 16 17 class E(C): 18 def test(self): 19 print('from E') 20 21 class F(D,E): 22 # def test(self): 23 # print('from F') 24 pass 25 f1=F() 26 f1.test() 27 print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 28 29 #新式类继承顺序:F->D->B->E->C->A 30 #经典类继承顺序:F->D->B->A->E->C 31 #python3中统一都是新式类 广度优先 32 #pyhon2中才分新式类与经典类 经典类就是深度优先
2 继承原理(python如何实现的继承)
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如
>>> F.mro() #等同于F.__mro__ [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
二 子类中调用父类的方法
方法一:指名道姓,即父类名.父类方法()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #_*_coding:utf-8_*_ 2 __author__ = 'Linhaifeng' 3 4 class Vehicle: #定义交通工具类 5 Country='China' 6 def __init__(self,name,speed,load,power): 7 self.name=name 8 self.speed=speed 9 self.load=load 10 self.power=power 11 12 def run(self): 13 print('开动啦...') 14 15 class Subway(Vehicle): #地铁 16 def __init__(self,name,speed,load,power,line): 17 Vehicle.__init__(self,name,speed,load,power) 18 self.line=line 19 20 def run(self): 21 print('地铁%s号线欢迎您' %self.line) 22 Vehicle.run(self) 23 24 line13=Subway('中国地铁','180m/s','1000人/箱','电',13) 25 line13.run()
方法二:super()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Vehicle: #定义交通工具类 2 Country='China' 3 def __init__(self,name,speed,load,power): 4 self.name=name 5 self.speed=speed 6 self.load=load 7 self.power=power 8 9 def run(self): 10 print('开动啦...') 11 12 class Subway(Vehicle): #地铁 13 def __init__(self,name,speed,load,power,line): 14 #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self) 15 super().__init__(name,speed,load,power) 16 self.line=line 17 18 def run(self): 19 print('地铁%s号线欢迎您' %self.line) 20 super(Subway,self).run() 21 22 class Mobike(Vehicle):#摩拜单车 23 pass 24 25 line13=Subway('中国地铁','180m/s','1000人/箱','电',13) 26 line13.run()
强调:二者使用哪一种都可以,但最好不要混合使用
了解部分:
即使没有直接继承关系,super仍然会按照mro继续往后查找
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#A没有继承B,但是A内super会基于C.mro()继续往后找 class A: def test(self): super().test() class B: def test(self): print('from B') class C(A,B): pass c=C() c.test() #打印结果:from B print(C.mro()) #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
指名道姓与super()的区别
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #指名道姓 2 class A: 3 def __init__(self): 4 print('A的构造方法') 5 class B(A): 6 def __init__(self): 7 print('B的构造方法') 8 A.__init__(self) 9 10 11 class C(A): 12 def __init__(self): 13 print('C的构造方法') 14 A.__init__(self) 15 16 17 class D(B,C): 18 def __init__(self): 19 print('D的构造方法') 20 B.__init__(self) 21 C.__init__(self) 22 23 pass 24 f1=D() #A.__init__被重复调用 25 ''' 26 D的构造方法 27 B的构造方法 28 A的构造方法 29 C的构造方法 30 A的构造方法 31 ''' 32 33 34 #使用super() 35 class A: 36 def __init__(self): 37 print('A的构造方法') 38 class B(A): 39 def __init__(self): 40 print('B的构造方法') 41 super(B,self).__init__() 42 43 44 class C(A): 45 def __init__(self): 46 print('C的构造方法') 47 super(C,self).__init__() 48 49 50 class D(B,C): 51 def __init__(self): 52 print('D的构造方法') 53 super(D,self).__init__() 54 55 f1=D() #super()会基于mro列表,往后找 56 ''' 57 D的构造方法 58 B的构造方法 59 C的构造方法 60 A的构造方法 61 '''
当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)
1111