面向对象三大特性——继承(原理及复用)

继承实现原理

  关于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中才分新式类与经典类
方法解析顺序(MRO)列表

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

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

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

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

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

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

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

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

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

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

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

子类重用父类方法及属性

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

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

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': '金箍棒'}
"""

方式二: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 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
"""

  运用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': '金箍棒'}
"""

  指名道姓与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
"""
 

猜你喜欢

转载自www.cnblogs.com/xiugeng/p/8918162.html