zoukankan      html  css  js  c++  java
  • 继承原理、派生重用

    一、继承实现原理

      关于python到底是如何实现继承,可以通过mro()来理解。首先定义多种继承示例代码:

    class A(object):
        def test(self):
            print('from A')
    
    class B(A):
        def test(self):
            print('from B')
    
    class C(A):
        def test(self):
            print('from C')
    
    class D(B):
        def test(self):
            print('from D')
    
    class E(C):
        def test(self):
            print('from E')
    
    class F(D,E):
        # def test(self):
        #     print('from F')
        pass
    f1=F()
    f1.test()
    print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    """
    from D
    (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    """
    #新式类继承顺序:F->D->B->E->C->A  广度优先
    #经典类继承顺序:F->D->B->A->E->C 深度优先
    #python3中统一都是新式类
    #pyhon2中才分新式类与经典类

    1、方法解析顺序(MRO)列表 

      对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表。

      F.mro()等同于上述示例代码中的F.__mor__

      python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。这个MRO列表的构造是通过一个C3线性化算法来实现,并遵循以下原则:

      1)子类会先于父类被检查

      2)多个父类会根据它们在列表中的顺序被检查

      3)如果对下一个类存在两个合法的选择,选择第一个父类。

    2、继承顺序

      在子类继承多个父类时,属性查找方式分深度优先广度优先两种。

      上图中,A为子类分别继承B,C,D类,经典类按照深度优先方法查找。

      因此继承顺序是:B->E->G->C->F->D(python2中有经典类和新式类)

      上图中,A为子类继承B、C、D三类,新式类按照广度优先方式查找。  

      新式类继承顺序:B->E->C->F->D->G (python3中只有新式类)

    二、子类重用父类方法及属性

      在子类派生的新的方法中重用父类的方法,有两种实现方式:

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

    class Hero:
        def __init__(self, nickname, life_value, aggresivity):
            self.nickname = nickname
            self.life_value = life_value
            self.aggresivity = aggresivity
    
        def attack(self, enemy):
            enemy.life_value -= self.aggresivity
    
    class Garen(Hero):
        camp = 'Demacia'
    
        def attack(self, enemy):  # 一旦重新定义了自己的属性且与父类重名,调用新增属性时,就以自己为准。
            Hero.attack(self, enemy)  # 指名道姓,不依赖于继承(一种重用方式)
            print('from Garen Class')
    
    class Riven(Hero):
        camp = 'Noxus'
    
    
    g = Garen('草丛伦', 100, 30)
    r = Riven('锐雯雯', 80, 50)
    
    print(r.life_value)
    g.attack(r)
    print(r.life_value)
    
    """
    80
    from Garen Class
    50
    """

      实例化子类添加自己独有特征__init__复用

    class Hero:
        def __init__(self, nickname, life_value, aggresivity):
            self.nickname = nickname
            self.life_value = life_value
            self.aggresivity = aggresivity
    
        def attack(self, enemy):
            enemy.life_value -= self.aggresivity
    
    class Garen(Hero):
        camp = 'Demacia'
    
        def __init__(self, nickname, life_value, aggresivity, weapon):  # 代码复用
            Hero.__init__(self, nickname, life_value, aggresivity)
            self.weapon = weapon
    
        def attack(self, enemy):
            Hero.attack(self, enemy)  # 指名道姓
            print('from Garen Class')
    
    g = Garen('草丛伦', 100, 30, '金箍棒')
    print(g.__dict__)
    
    """
    {'nickname': '草丛伦', 'life_value': 100, 'aggresivity': 30, 'weapon': '金箍棒'}
    """

    2、方式二:super()  (依赖继承)

    (1)什么是super?

      super() 函数是用于调用父类(超类)的一个方法。

      super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

      MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

    (2)语法

    super(type[, object-or-type])
    
    参数:
      type -- 类。
      object-or-type -- 类,一般是 self
    

    (3)应用示例

    class Hero:
        def __init__(self, nickname, life_value, aggresivity):
            self.nickname = nickname
            self.life_value = life_value
            self.aggresivity = aggresivity
    
        def attack(self, enemy):
            enemy.life_value -= self.aggresivity
    
    class Garen(Hero):
        camp = 'Demacia'
    
        def attack(self, enemy):
            super(Garen, self).attack(enemy)  # 依赖继承
            print('from Garen Class')
    
    class Riven(Hero):
        camp = 'Noxus'
    
    g = Garen('草丛伦', 100, 30)
    r = Riven('锐雯雯', 80, 50)
    
    g.attack(r)
    print(r.life_value)
    """
    from Garen Class
    50
    """

    (4)运用super()实例化子类添加独有特征

    class Hero:
        def __init__(self, nickname, life_value, aggresivity):
            self.nickname = nickname
            self.life_value = life_value
            self.aggresivity = aggresivity
    
        def attack(self, enemy):
            enemy.life_value -= self.aggresivity
    
    class Garen(Hero):
        camp = 'Demacia'
        def __init__(self, nickname, life_value, aggresivity, weapon):  # 代码复用
            # Hero.__init__(self, nickname, life_value, aggresivity)
            # super(Garen, self).__init__(nickname, life_value, aggresivity)  # python2必须这么写
            super().__init__(nickname, life_value, aggresivity)  # python3可以这么简写
            self.weapon = weapon
    
        def attack(self, enemy):
            Hero.attack(self, enemy)  # 指名道姓
            print('from Garen Class')
    
    g = Garen('草丛伦', 100, 30, '金箍棒')
    print(g.__dict__)
    """
    {'nickname': '草丛伦', 'life_value': 100, 'aggresivity': 30, 'weapon': '金箍棒'}
    """

    3、指名道姓与super()区别

      指名道姓是跟继承没有关系,而方式二的super()是依赖于继承的,并且即使没有直接继承关系,super仍然会按照mro继续往后查找。

      super与mro列表的关系

    class A:
        def f1(self):
            print('from A')
            super().f1()   # super不管A的继承关系,按照C的MRO列表,继续往后找:B
    
    class B:
        def f1(self):
            print('from B')
    
    class C(A,B):
        pass
    
    print(C.mro())
    """
    [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
    """
    c = C()
    c.f1()
    """
    from A
    from B
    """

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

     
  • 相关阅读:
    Kafka如何保证读写的跨分区与会话
    Kafka topic中的partition的leader选举
    Kafka为什么这么快
    sqoop导入导出
    为什么要用redis去重
    bypass SortShuffleManager的bypass运行机制
    大数据常用端口号
    vector基础
    【拓扑排序】
    【POJ】Crazy Search(hash)
  • 原文地址:https://www.cnblogs.com/xiugeng/p/8918162.html
Copyright © 2011-2022 走看看