• 继承实现原理


    继承实现的原理

    一继承顺序

    在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

  • 相关阅读:
    hashcode与equals的关系,hashcode的作用
    Exception和Error的区别
    spring下的beanutils.copyProperties方法是深拷贝还是浅拷贝?可以实现深拷贝吗?
    AopContext.currentProxy()该用法的意义
    spring如何解决循环依赖
    springboot注解以及手动使用事务
    反射中,Class.forName和ClassLoader区别
    ThreadLocal真的会造成内存泄露?
    Vue 插槽(slot)详细介绍(对比版本变化,避免踩坑)
    MySQL统计近7天(两周、一个月等)数据,没有数据显示为0
  • 原文地址:https://www.cnblogs.com/caochao-/p/8536323.html
Copyright © 2020-2023  润新知