004---继承与派生

初识继承

什么是继承

  • 继承指的是类与类之间的关系,是一种什么是什么的关系。
  • 继承是用来创建新类的一种方式。在python中,新建的类可以继承一个或多个父类。
  • 父类又叫做基类或超类、新建的类又叫做子类或派生类

种类:多继承和单继承

class P1:                 # 定义父类P1
    pass


class P2:                 # 定义父类P2
    pass


class P_chirdren1(P1):    # 单继承:基类是P1,派生类是P_chirdren1
    pass


class P_chirdren2(P1, P2):# 多继承:基类是P1、P2, 派生类是P_chirdren2
    pass

查看继承

# __base__只查看从左到右继承的第一个父类
# __bases__则是查看子类继承的所有父类
print(P_chirdren1.__base__)     # class '__main__.P1'
print(P_chirdren2.__base__)     # class '__main__.P1'
print(P_chirdren2.__bases__)    # (class '__main__.P1', class '__main__.P2')

新式类和经典类

  • 在python2当中
    • 经典类:没有继承object,以及他的子类都是经典类
    • 新式类:继承了object,以及她的子类都是新式类
  • 在python3当中
    • 无论是否继承object,都默认继承object,即python3中所有类都是新式类

继承和抽象(先抽象和继承)

抽象就是把多个类相似的特征和行为抽取出来,抽取到父类,然后继承它。

  • 继承:是基于抽象的结果
  • 抽象:只是分析和设计的过程中,一个动作或技巧,通过抽象可以得到类。

派生

子类继承了父类的属性和方法,当然也可以添加自己新的属性和方法或者重写,不会影响到父类。但是调用的时候就会以自己的为准,不会调用父类的。

class Hero:
    """
    英雄类
    """
    def __init__(self, nickname, life_value, aggresivity):
        
        self.nickname = nickname
        self.life_value = life_value
        self.aggresivity = aggresivity

    def acctack(self, enemy):
        enemy.life_value -= self.aggresivity
        if enemy.life_value < 0:
            print('%s 取得胜利,杀死了%s' % (self.nickname, enemy.nickname))


class Garen(Hero):
    """
    盖伦类
    """
    # 声明一个新属性
    camp = 'Demacia'

    def acctack(self):
        """
        重写父类当中的acctack()。
        :return: 
        """
        print('from Garen')


class Riven(Hero):
    """
    瑞文类
    """
    camp = 'Noxus'


g1 = Garen('葛小伦', 21, 30)
print(g1.camp)  # Demacia
g1.acctack()    # from Garen

继承的实现原理

对于定义的每一个类。python会计算出一个方法解析顺序列表(mro),它代表了类继承的顺序,也代表了子类的属性和方法的查找顺序。

class A:
    def test(self):
        print('A')


class B(A):
    def test(self):
        print('B')


class C(A):
    def test(self):
        print('C')


class D(B):
    def test(self):
        print('D')


class E(C):
    def test(self):
        print('E')


class F(D, E):
    def test(self):
        # print('D')
        pass
# 新式类 D-->B-->E-->C-->A
print(F.mro())        # (class '__main__.F', class '__main__.D', class '__main__.B', class '__main__.E', class '__main__.C', class '__main__.A', class 'object')
print(F.__mro__)      # [class '__main__.F', class '__main__.D', class '__main__.B', class '__main__.E', class '__main__.C', class '__main__.A', class 'object']
  • mro:Method Resolution Order,即方法解析顺序,是python处理二义性问题的算法,我们不需要关心算法内部怎么实现。只要知道属性的查找方式有两种:深度优先和广度优先。
  • 注意:只有新式类才有mro这个属性,经典类没有。

在子类中调用父类的方法

  • 指名道姓(不依赖继承):父类.父类method(self,*args,**kwargs)
class Vehicle(object):
    """
    交通工具类
    """
    country = 'China'

    def __init__(self, name, speed, load, power):
        self.name = name
        self.speed = speed
        self.load = load
        self.power = power

    def run(self):
        print('开动了')


class Subway(Vehicle):
    """
    地铁类
    """

    def __init__(self, name, speed, load, power, line):
        # 调用父类的初始化方法
        Vehicle.__init__(self, name, speed, load, power)
        self.line = line

    def run(self):
        print('地铁%s欢迎你' % self.line)
        Vehicle.run(self)

s = Subway('北京','180km/h','100人/节','电','1号线')
s.run()
  • super(依赖继承)
class Vehicle(object):
    """
    交通工具类
    """
    country = 'China'

    def __init__(self, name, speed, load, power):
        self.name = name
        self.speed = speed
        self.load = load
        self.power = power

    def run(self):
        print('开动了')


class Subway(Vehicle):
    """
    地铁类
    """

    def __init__(self, name, speed, load, power, line):

        # 相当于实例本身,在python中:super() == super(Subway,self)
        # super(Subway, self).__init__(name,speed,load,power)
        super().__init__(name,speed,load,power)
        self.line = line

    def run(self):
        print('地铁%s欢迎你' % self.line)
        # super(Subway, self).run()
        super().run()
s = Subway('北京','180km/h','100人/节','电','1号线')
s.run()
  • 需要注意的是,在多继承的情况下。super并不是一味地只找父类。而是按照子类的mro顺序去查找。
# 误区
class A:
    def f1(self):
        print('A')
        super().f1()


class B:
    def f1(self):
        print('B')


class C(A, B):
    pass


c = C()
c.f1()  # A  B    super会让人觉得他继承了B,就去B类寻找f1方法。  实际上,super依赖继承,根据c的mRo列表一步步找。
print(C.__mro__) # (class '__main__.C', class '__main__.A', class '__main__.B', class 'object')

继承的优点

  • 最大的优点:解决了代码冗余,代码重用,节省了代码
原文地址:https://www.cnblogs.com/xjmlove/p/10320731.html