继承实现原理

继承实现的原理

一继承顺序

在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)

如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先

 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.如果对下一个类存在两个合法的选择,选择第一个父类

二 子类中调用父类的方法

方法一:指名道姓,即父类名.父类方法()

 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()
View Code

方法二:super()

 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()
View Code

强调:二者使用哪一种都可以,但最好不要混合使用 

了解部分:

即使没有直接继承关系,super仍然会按照mro继续往后查找

#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'>]
View Code

指名道姓与super()的区别

 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 '''
View Code

当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

1111

posted @ 2018-03-09 21:10  无名!  阅读(898)  评论(0编辑  收藏  举报