zoukankan      html  css  js  c++  java
  • python-类继承与重用

    类的继承与重用

    一、什么是继承?

      1、继承是类与类间的关系。

      2、是一种什么‘’是‘’什么的关系。

      3、继承功能就是用来解决代码重用的问题。

    1、继承: 是一种创建新类的方式,

      python中,

      1、新建的类可以继承一个或多个父类。

      2、父类可以成为基类或超类。

      3、所新建的类称为子类或派生类。

    2、类继承的数量:

      python中类的继承分为:继承一个或多个。

    class ParentClass1: #定义父类
        pass
    
    class ParentClass2: #定义父类
        pass
    
    class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
        pass
    
    class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
        pass
    类继承1个或多个父类

    3、查看继承:

      python中可以通过__base__命令可以查看

    SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    #(<class '__main__.ParentClass1'>,)
    SubClass2.__bases__
    #(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
    __base__方法查看继承了什么类

    4、如果没有指定基类,python的类会默认继承object类,因为object类是所有python类的基类。

     ParentClass1.__bases__ #由于ParentClass1这个类中没有继承类,python默认会继承object类,打印如下:

     #(<class 'object'>,)

    5、经典类与新式类,及其区别。

      1、python2——才有经典与新式的区分。python3——统一都是新式类。

      2、python2——没有显式继承object的类的,以及该类的子类,都是经典类。声明了object的类及子类,都是新式类。

      3、python3——无论是否继承object,都默认继承object,因为python3所有的类都是新式类。

      4、经典类与新式类的主要区别在:

         经典类——多继承的情况,要查找的属性不存在时,按照深度优先。

         新式类——。。。。。。。按照广度优先。

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

       抽象——抽取类似或相似的部分。

       继承——是抽象后的结果,通过编程来实现,一定要先有抽象的过程,才能有继承的结果。

    抽象的过程——提取对象相似的特征构造成类,然后通过类,再抽象成这些类的父类。

    继承的过程如下图。

    三、继承与重用性

      我们定义了一个类称A,再定义一个新类B,如果B这个类中有大部分的内容与A相同时。

      我们就可以用到类的继承的概念。通过继承,B就会遗传A所有的属性(包括数据和函数),从而实现代码重用。

    class Hero:
        def __init__(self,nickname,aggressivity,life_value):
            self.nickname=nickname
            self.aggressivity=aggressivity
            self.life_value=life_value
    
        def move_forward(self):
            print('%s move forward' %self.nickname)
    
        def move_backward(self):
            print('%s move backward' %self.nickname)
    
        def move_left(self):
            print('%s move forward' %self.nickname)
    
        def move_right(self):
            print('%s move forward' %self.nickname)
    
        def attack(self,enemy):
            enemy.life_value-=self.aggressivity
    class Garen(Hero):
        pass
    
    class Riven(Hero):
        pass
    
    g1=Garen('草丛伦',100,300)
    r1=Riven('锐雯雯',57,200)
    
    print(g1.life_value) #结果:300
    r1.attack(g1)
    print(g1.life_value) #结果:243
    通过继承实现代码重用

    注意:1、用已有的类建立新的类,可大大节省代码。

         2、 我们也可以继承被人的类如标准库,来定制新的类型。

    四、属性查找 

    class Foo:
        def f1(self):
            print('Foo.f1')
    
        def f2(self):  # 4、找到f2了执行命令
            print('Foo.f2')
            self.f1()  # 5、因为self 指的是对象本身,所以是b.f1()
            # 6、从bar()里找到f1() 所以打印Bar.f1
    
    
    class Bar(Foo):  # 3、在自己的类里面也没找到,所以在父类FOO里找
        def f1(self):
            print('Bar.f1')
    
    
    b = Bar()  # 2、从自己的类里面查找f1()
    b.f2()  # 1、从对象b里查找f1(),由于没有定义__init__方法,所以找不到。
    属性查找顺序

    查找说明:

      1、程序实例化了b=Bar()这个对象。

      2、b.f2()这个方法在b 这个类里找不到,就找从FOO这个类里找.

      3、在父类FOO中找到了f2()方法并执行。

      4、当执行self.f1()时,由于self指的是类本身即Bar,所以执行Bar下的f1()。

    五、派生

    类可以继承父类的属性,也可以自己新属于自己的属性,一旦定义的属性名与父类的重名,调用的时候以自己的为准。

    # 派生
    class Hero:
        def __init__(self, nickname, aggressivity, life_value):
            self.nickname = nickname
            self.aggressivity = aggressivity
            self.life_value = life_value
    
        def move_forward(self):
            print('%s move forward' % self.nickname)
    
        def move_backward(self):
            print('%s move backward' % self.nickname)
    
        def move_left(self):
            print('%s move forward' % self.nickname)
    
        def move_right(self):
            print('%s move forward' % self.nickname)
    
        def attack(self, enemy):
            enemy.life_value -= self.aggressivity
    
    
    class Riven(Hero):
        camp = 'Noxus'
    
        def attack(self, enemy):  # 在自己这里定义新的attack,不再使用父类的attack,且不会影响父类
            print('from riven', enemy)
    
        def fly(self):  # 在自己这里定义新的
            print('%s is flying' % self.nickname)
    
    
    r1 = Riven('锐雯雯', 57, 200)
    print(r1.attack(10))
    派生用法

    注意:在子类中,如果新建了与父类重名的函数属性,在调用时也应该按照函数调用方式进行,即有多少个参数应传多少个值

    六、继承的实现原理

    Python实现继承的原理是在用户定义类的时候,计算并生成一个MRO线性列表。主要有如下原则:

      1、子类优先于父类查找

      2、多个父类会根据MRO列表顺序查找

      3、如果下一个类对应两个合法选项,第一个父类优先。

    注意:C和java只支持继承一个父类,python支持继承多个父类,如果继承多个父类,查找方式有两种:

      经典类——深度优先:

      新式类——广度优先

    在python3查找顺序练习:

    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()  # F D B E C A
    
    print(F.__mro__)  # 只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    
    # 新式类继承顺序:F->D->B->E->C->A
    # 经典类继承顺序:F->D->B->A->E->C
    # python3中统一都是新式类
    # pyhon2中才分新式类与经典类
    py3多个父类查找方式

    由于py3的类统一是新式类,按照广度优先查找顺序,所以查找顺序为F=>D=>B=>E=>C=>A

    如果是在py2,是经典类,按深度优先,所以是这样的F=>D=>B=>A=>E=>C

    七、子类中调用父类的方法

      有两种方法:

      1、指名道姓调用

    # 1、指名道姓方式引用,这种方式跟继承没有关系,只是简单的类的函数属性的引用
    class Vehicle:  # 定义交通工具类
        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)
    
    
    line13 = Subway('中国地铁', '180m/s', '1000人/箱', '', 13)
    line13.run()
    指名道姓引用类函数属性

    注意:这样的调用方式,跟继承没有关系,相当于引用了类的函数属性,需要什么参数就要传什么参数。

      2、super()方法调用

    # 调用方法二:super()
    #A没有继承B,但是A内super会基于C.mro()继续往后找
    class A:
        def test(self):
            print('test A')
            super().test()
    class B:
        def test(self):
            print('from B')
    class C(A,B):
        # print('test c')
        pass
    
    c=C()
    c.test() #打印结果:from B
    Super()方法调用

    注意:用super方法调用,是依赖于继承的,即使两个父类间没有继承关系,都会从子类的继承关系的MRO表继续往后找。

  • 相关阅读:
    go通道小案例
    go执行cmd命令并获取输出内容
    vue快速生成二维码
    vue.js数字简化 万转化k显示
    uniapp实现小程序获取用户信息
    实现图片预加载功能
    C# MD5加密字符串方法
    一个封装的 HttpClientHelper
    简易通过队列存储并异步打日志实现
    变量
  • 原文地址:https://www.cnblogs.com/AYxing/p/8996824.html
Copyright © 2011-2022 走看看