Python3.7之继承

Python3.7之继承

一、什么叫继承

继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超

类,新建的类称为派生类或子类。子类会“”遗传”父类的属性,从而解决代码重用问题。

单继承与多继承

class Parent1:
    pass


class Parent2:
    pass


class Children1(Parent1):
    pass


class Children2(Parent1, Parent2):
    pass


print(Children2.__bases__)
print(Children1.__bases__)

'''
(<class '__main__.Parent1'>, <class '__main__.Parent2'>)
(<class '__main__.Parent1'>,)
'''

经典类与新式类

只有在python2中才分新式类和经典类,python3中统一都是新式类

在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类

在python2中,显式地声明继承object的类,以及该类的子类,都是新式类

在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式

二、继承与抽象(先抽象再继承)

抽象即抽取类似或者说比较像的部分。

抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类

三、继承与重用性

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相

同时,我们不可能从头开始写一个类B,这就用到了类的继承的概念。

通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

class Hero:
    def __init__(self, nickname, attack_value, life_value):
        self.nickname = nickname
        self.attack_value = attack_value
        self.life_value = life_value

    def attack(self, enemy):
        enemy.life_value -= self.attack_value


class Garen(Hero):
    camp = 'Demacia'


class Riven(Hero):
    camp = 'Noxus'


role1 = Garen('A', 50, 100)
role2 = Riven('B', 30, 80)
print(role1.camp)
print(role2.camp)
role1.attack(role2)
print(role2.life_value)

属性查找顺序

先从实例中找,然后去类中找,然后再去父类中找...直到最顶级的父类。

class Foo:
    def f1(self):
        print('f1 From Foo')

    def f2(self):
        print('f2 from Foo')
        self.f1()  # b.f1,此时self为实例b


class Bar(Foo):
    def f1(self):
        print('f1 from Bar')


b = Bar()
b.f2()

'''
f2 from Foo
f1 from Bar
'''

方法解析顺序(mro)

四、继承的实现原理

Python中子类可以同时继承多个父类,如果继承了多个父类,那么属性的查找方式有两种,分别是:深度优先和

广度优先。

我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

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

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

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

当类是经典类时,多继承情况下,在要查找的属性不存在时,会按照深度优先的方式查找下去;

当类是新式类时,多继承情况下,在要查找的属性不存在时,会按照广度优先的方式查找下去。

五、在子类中调用父类的方法

1.父类名.父类方法()

非绑定方法调用

class Garen(Hero):
    def __init__(self, nickname, attack_value, life_value, skin):
        Hero.__init__(self, nickname, attack_value, life_value)
        # 调用父类功能,注意这里必须要有self
        self.skin = skin  # 新属性

    def attack(self, enemy):
        Hero.attack(self, enemy)  # 调用父类功能,参数必须与父类一致
        print('From Garen')  # 自己新的功能
    camp = 'Demacia'

2. super()

builtin函数super

class Hero:
    camp = 'Hero'

    def __init__(self, nickname, attack_value, life_value):
        self.nickname = nickname
        self.attack_value = attack_value
        self.life_value = life_value

    def attack(self, enemy):
        enemy.life_value -= self.attack_value


class Garen(Hero):
    def __init__(self, nickname, attack_value, life_value, skin):
        # super(Garen,self) 就相当于实例本身 在python3中super()等同于super(Garen,self)
        super().__init__(nickname, attack_value, life_value)
        self.skin = skin

    def attack(self, enemy):
        super().attack(enemy)
        print('From Garen')
    camp = 'Demacia'


class Riven(Hero):
    camp = 'Noxus'


role1 = Garen('A', 50, 100, 'A1')
role2 = Riven('B', 30, 80)
print(role1.skin)
role1.attack(role2)
print(role2.life_value)

这两种方式的区别是:方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,并且即使没有直接继承

关系,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())
'''
from B
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
'''

四、继承的好处

提高代码的复用。

五、继承的弊端

可能特殊的本类又有其他特殊的地方,又会定义一个类,其下也可能再定义类,这样就会造成继承的那条线越来越

长,使用继承的话,任何一点小的变化也需要重新定义一个类,很容易引起类的爆炸式增长,产生一大堆有着细微不同

的子类. 所以有个“多用组合少用继承”的原则。

猜你喜欢

转载自www.cnblogs.com/rainbow-ran/p/12204859.html
今日推荐