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列表

     
  • 相关阅读:
    The Quad
    将OrCAD Capture CIS的设计文件(.dsn)导入到PADS Logic VX.2.3
    OrCAD Capture CIS 16.6 将版本16.6的设计文件另存为版本16.2的设计文件
    Eclipse IDE 添加jar包到Java工程中
    PADS Logic VX.2.3 修改软件界面语言
    切换Allegro PCB Editor
    Allegro PCB Design GXL (legacy) 将brd文件另存为低版本文件
    Allegro PCB Design GXL (legacy) 设置自动保存brd文件
    Could not create an acl object: Role '16'
    windows 下apache开启FastCGI
  • 原文地址:https://www.cnblogs.com/xiugeng/p/8918162.html
Copyright © 2011-2022 走看看