• 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')
    

    继承的优点

    • 最大的优点:解决了代码冗余,代码重用,节省了代码
  • 相关阅读:
    强烈免费25款商务logo设计模板 java程序员
    16个帮助你高效测试响应式设计界面的工具 java程序员
    一个帮助你生成iOS文件夹效果的jQuery插件 AppFolders java程序员
    Linq 实现左连接,右连接 java程序员
    一个帮助你实现pinterest页面布局的jQuery插件 jQuery.Shapeshift java程序员
    基于HTML5实现的超酷摄像头(HTML5 webcam)拍照功能 photobooth.js java程序员
    30个让你保持好身材的iphone健康应用程序 java程序员
    一个实体对象不能由多个 IEntityChangeTracker 实例引用 解决办法 java程序员
    2012年十一月GBin1 web技术热点荟萃 java程序员
    超棒的20款javascript工具提示条(tooltips)类库 java程序员
  • 原文地址:https://www.cnblogs.com/xjmlove/p/10320731.html
Copyright © 2020-2023  润新知