• Python面向对象2-继承-


    目标

    • 继承的概念
    • 单继承
    • 多继承
    • 子类重写父类的同名属性和方法
    • 子类调用父类的同名属性和方法
    • 多层继承
    • super()
    • 私有属性和私有方法

    一. 继承的概念

    生活中的继承,一般指的是子女继承父辈的财产。

    • 拓展1:经典类或旧式类

    不由任意内置类型派生出的类,称之为经典类。 [经典类 甚至连Object父类都没有了]

    class 类名:
        代码
        ......
    
    • 1
    • 2
    • 3
    • 拓展2:新式类
    class 类名(object):
      代码
    
    • 1
    • 2

    区别:

    Python中类分两种:旧式类和新式类:
    新式类都从object继承,经典类不需要。
    新式类的MRO(method resolution order 基类搜索顺序)算法采用C3算法广度优先搜索,而旧式类的MRO算法是采用深度优先搜索
    新式类相同父类只执行一次构造函数,经典类重复执行多次。

    Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:

    # 父类A
    class A(object):
        def __init__(self):
            self.num = 1
    
        def info_print(self):
            print(self.num)
    
    # 子类B
    class B(A):
        pass
    
    
    result = B() # 继承了父类A的所有方法
    result.info_print()  # 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在Python中,所有新式类默认继承object类object类是顶级类或基类;其他子类叫做派生类

    二. 单继承

    故事主线:一个煎饼果子老师傅,在煎饼果子界摸爬滚打多年,研发了一套精湛的摊煎饼果子的技术。师父要把这套技术传授给他的唯一的最得意的徒弟。

    分析:徒弟是不是要继承师父的所有技术?

    # 1. 师傅类
    class Master(object):
        def __init__(self):
            self.kongfu = '[古法煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    # 2. 徒弟类
    class Prentice(Master):
        pass
    
    # 3. 创建对象 daqiu
    daqiu = Prentice()
    # 继承了师傅的方法
    daqiu.make_cake()  # 运用[古法煎饼果子配方]制作煎饼果子
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    三. 多继承 [python又支持多继承了]

    故事推进:daqiu 是个爱学习的好孩子,想学习更多的煎饼果子技术,于是,在百度搜索,报班学习煎饼果子技术。

    所谓多继承意思就是一个类同时继承了多个父类。

    class Master(object):
        def __init__(self):
            self.kongfu = '[古法煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
        def sayPlay(self):
            print("老师傅独有技能:唱戏曲")
    
    class School(object):
        def __init__(self):
            self.kongfu = '[武大煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
        def findWork(self):
            print('学校独有技能:找工作')
    
    
    
    class Prentice(School,Master): # 多继承 同时继承2个类
        pass
    
    daqiu = Prentice()
    # 先是两位老师傅那分别学的独家技能
    daqiu.sayPlay()
    daqiu.findWork() 
    
    # 再是共同的技能
    daqiu.make_cake() # 默认使用第一个父类的同名属性和方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    注意:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法。

    四. 子类重写父类同名方法和属性

    故事:daqiu掌握了师父和培训的技术后,自己潜心钻研出自己的独门配方的一套全新的煎饼果子技术。

    class Master(object):
        def __init__(self):
            self.kongfu = '[古法煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    class School(object):
        def __init__(self):
            self.kongfu = '[黑马煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    # 独创配方
    class Prentice(School, Master):
        def __init__(self):
            self.kongfu = '[独创煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    daqiu = Prentice()
    print(daqiu.kongfu)
    daqiu.make_cake()
    
    # 为了方便且快速地看清继承关系和顺序,可以用__mro__方法来获取这个类的调用顺序。
    print(Prentice.__mro__)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。(重写了嘛 当然是啦 就近 更近)
    为了方便且快速地看清继承关系和顺序,可以用__mro__方法来获取这个类的调用顺序。

    五. 子类调用父类的同名方法和属性

    比较麻烦,要专门写一个方法调用
    只是记得可以调就是了

    故事:很多顾客都希望也能吃到古法和黑马的技术的煎饼果子。

    class Master(object):
        def __init__(self):
            self.kongfu = '[古法煎饼果子配方'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    class School(object):
        def __init__(self):
            self.kongfu = '[武大煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    # 重写了 如何还能调用父类方法呢
    class Prentice(School,Master):
        def __init__(self):
            self.kongfu = '{独创煎饼果子配方}'
    
        # 重写父类方法
        def make_cake(self):
            # 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
            # ★ 不加此行 调用了下面的的方法后 再调用这个方法就会有问题  kongfu的值会被频繁的改
            self.__init__()
            print(f'运用{self.kongfu}制作煎饼果子')
    
        # 调用父类方法,但是为了保证调用的也是父类的属性,必须在调用方法前调用父类的初始化
        def make_master_cake(self):
            Master.__init__(self)
            Master.make_cake(self)
    
        def make_school_cake(self):
            School.__init__(self)
            School.make_cake(self)
    
    
    # Master.make_cake() # 外面可以直接调 但是报错 因为没有对象啊
    
    daqiu = Prentice()
    daqiu.make_cake()
    daqiu.make_master_cake()
    daqiu.make_school_cake()
    # 对象.方法() 会自动将当前对象当作self传进去
    
    daqiu.make_cake() # self.kongfu还是保持School的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    对象.方法() 会自动将当前对象当作self传进去

    在这里插入图片描述

    六. 多层继承

    故事:N年后,daqiu老了,想要把所有技术传承给自己的徒弟。

    class Master(object):
        def __init__(self):
            self.kongfu = '[古法煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    class School(object):
        def __init__(self):
            self.kongfu = '[黑马煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    class Prentice(School, Master):
        def __init__(self):
            self.kongfu = '[独创煎饼果子配方]'
    
        def make_cake(self):
            self.__init__()
            print(f'运用{self.kongfu}制作煎饼果子')
    
        def make_master_cake(self):
            Master.__init__(self)
            Master.make_cake(self)
    
        def make_school_cake(self):
            School.__init__(self)
            School.make_cake(self)
    
    
    # 徒孙类
    class Tusun(Prentice):
        pass
    
    
    xiaoqiu = Tusun()
    
    xiaoqiu.make_cake()
    
    xiaoqiu.make_school_cake()
    
    xiaoqiu.make_master_cake()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

    七. super()调用父类方法

    继承关系: Master->School->Prentice (爷->父->儿)
    场景: Master有make_cake方法,School重写了make_cake方法,Prentice又重写了make_cake方法
    目前有3个make_cake方法 我想在Prentice类里面同时能调用到这3个make_cake方法,怎么做呢?

    方法一:原始笨方法

    class Master(object):
        def __init__(self):
            self.kongfu = '[古法煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    class School(Master):
        def __init__(self):
            self.kongfu = '[黑马煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    class Prentice(School):
        def __init__(self):
            self.kongfu = '[独创煎饼果子技术]'
    
        def make_cake(self):
            self.__init__()
            print(f'运用{self.kongfu}制作煎饼果子')
    
        # 代码在这  前面都直接复制的,一样(唯一改了一个继承关系: School(Master):)
        # 一次性调用父类的同名属性和方法
        def make_old_cake(self):
            # 方法一:代码冗余;父类类名如果变化,这里代码需要频繁修改
            # 分别调用两次init和两次对应方法
            Master.__init__(self)
            Master.make_cake(self)
            School.__init__(self)
            School.make_cake(self)
    
    daqiu = Prentice()
    daqiu.make_old_cake()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在这里插入图片描述

    方法二:super带参写法

    好多了 但非最佳, 也不是很推荐

    注意:使用super() 可以自动查找父类。调用顺序遵循 __mro__ 类属性的顺序。比较适合单继承使用。
    super指的是直接父类 (子的super=父,父的super=爷)

    class Master(object):
        def __init__(self):
            self.kongfu = '[古法煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    class School(Master):
        def __init__(self):
            self.kongfu = '[黑马煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
            # 为了能逐级调用到父类的方法 这里必须super调用一下
            # 方法2: super带参 这里也要加代码
            super(School,self).__init__()
            super(School,self).make_cake()
    
    
    class Prentice(School):
        def __init__(self):
            self.kongfu = '[独创煎饼果子技术]'
    
        def make_cake(self):
            self.__init__()
            print(f'运用{self.kongfu}制作煎饼果子')
    
        # 本节代码在这: 一次性调用父类的同名属性和方法
        def make_old_cake(self):
            # 方法二: super
            # 方法2 带参写法: super(当前类名,self).函数
            super(Prentice,self).__init__()
            super(Prentice,self).make_cake() # 运用[黑马煎饼果子配方]制作煎饼果子
            # 确实调用到了父类 但是只调用到了爸爸,没有调用到爷爷
            # 怎么办呢? 答: 爸爸方法里也要这么写一份  (我的super是爸爸,爸爸的super才是爷爷  super是直接父类)
    
    
    daqiu = Prentice()
    daqiu.make_old_cake()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    在这里插入图片描述

    方法三:super无参写法 (推荐、以后的写法)

    class Master(object):
        def __init__(self):
            self.kongfu = '[古法煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    class School(Master):
        def __init__(self):
            self.kongfu = '[黑马煎饼果子配方]'
    
        def make_cake(self):
            print(f'运用{self.kongfu}制作煎饼果子')
    
            # 方法3 父类要加的代码  就是每个子类都主动调用一下父类的该方法即可
            super().__init__()
            super().make_cake()
    
    class Prentice(School):
        def __init__(self):
            self.kongfu = '[独创煎饼果子技术]'
    
        def make_cake(self):
            self.__init__()
            print(f'运用{self.kongfu}制作煎饼果子')
    
        # 方法三: 无参super
        def make_old_cake(self):
            super().__init__()
            super().make_cake()
    
    
    
    daqiu = Prentice()
    daqiu.make_old_cake()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在这里插入图片描述

    注意:使用super() 可以自动查找父类。调用顺序遵循 __mro__ 类属性的顺序。比较适合单继承使用。
    super指的是直接父类 (子的super=父,父的super=爷)

    八. 私有权限

    8.1 定义私有属性和方法

    在Python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类。

    故事:daqiu把技术传承给徒弟的同时,不想把自己的钱(2000000个亿)继承给徒弟,这个时候就要为这个实例属性设置私有权限。

    设置私有权限的方法:在属性名和方法名 前面 加上两个下划线 __。
    不愧是python 命名规则就是私有属性的语法

    class Father(object):
        def __init__(self):
            self.kongfu = '[独创热干面配方]'
            # 定义私有属性
            self.__money = 2000000
    
        # 定义私有方法
        def __info_print(self):
            print(self.kongfu)
            print(self.__money)
    
        def make_cake(self):
            self.__init__()
            print(f'运用{self.kongfu}制作煎饼果子')
    
    class Son(Father):
        def print_info(self):
            print(self.kongfu) # 能继承到的 都能正常访问 但一定得"对象.xx"的形式 因为都属于对象
            self.make_cake()
            # self.__money # 报错 私有的怎么也访问不到
            # self.__info_print() # 报错 私有的怎么也访问不到
    
    
    fa = Father()
    #print(fa.__money)  # AttributeError: 'Father' object has no attribute '__money'
    #fa.__info_print  # AttributeError: 'Father' object has no attribute '__info_print'
    #结论: 私有属性和私有方法都不能在类外访问
    
    ## 非私有属性方法才可以正常访问
    print(fa.kongfu)
    fa.make_cake()
    
    
    son = Son()
    # print(son.__money) # AttributeError: 'Son' object has no attribute '__money'
    # son.__info_print() # AttributeError: 'Son' object has no attribute '__info_print'
    #结论: 私有属性和私有方法 肯定不会被继承的
    
    # 非私有属性和方法 才可以正常被继承
    print(son.kongfu)
    son.make_cake()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    注意:私有属性和私有方法只能在类里面访问和修改。

    8.2 获取和修改私有属性值

    在Python中,一般定义函数名get_xx用来获取私有属性,定义set_xx用来修改私有属性值。

    
    class Prentice(object):
        def __init__(self):
            self.kongfu = '[独创煎饼果子配方]'
            self.__money = 2000000
    
        # 获取私有属性
        def get_money(self):
            return self.__money # 和java一样 利用私有属性只能在类内访问这一特点
    
        # 修改私有属性
        def set_money(self,money):
            self.__money = money # 和java一样 利用私有属性只能在类内访问这一特点
    
    
        def __info_print(self):
            print(self.kongfu)
            print(self.__money)
    
        def make_cake(self):
            self.__init__()
            print(f'运用{self.kongfu}制作煎饼果子')
    
    
    # 徒孙类
    class Tusun(Prentice):
        pass
    
    xq = Tusun()
    # 私有属性用访问器访问
    print(xq.get_money()) # 2000000
    xq.set_money(10)
    print(xq.get_money()) # 10
    
    # 非私有属性正常访问
    print(xq.kongfu) # [独创煎饼果子配方]
    xq.kongfu= '[独创热干面配方]'
    print(xq.kongfu) # [独创热干面配方]
    # print(Prentice.kongfu) # type object 'Prentice' has no attribute 'kongfu'
                            # 都是非静态的成员 属于对象 而不属于类
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    在这里插入图片描述

    九. 总结

    • 继承的特点

      • 子类默认拥有父类的所有属性和方法
      • 子类重写父类同名方法和属性
      • 子类调用父类同名方法和属性
    • super()方法快速调用父类方法

    • 私有权限

      • 不能继承给子类的属性和方法需要添加私有权限
      • 语法
      class 类名():
        # 私有属性
        __属性名 =# 私有方法
        def __函数名(self):
          代码
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    小笔记:

    对象.方法() 会自动将当前对象当作self传进去

  • 相关阅读:
    数据可视化(七):Pandas香港酒店数据高级分析,涉及相关系数,协方差,数据离散化,透视表等精美可视化展示
    【MySQL】基本查询(三)聚合函数+group by
    wpa_cli辅助工具的使用
    CVPR2022| BodyMap可用于换装,Vision Transformers 又立功!
    Codeforces Round #813 (Div. 2)
    G.711语音编解码器详解
    Linux基础IO
    Spring Boot3 web开发
    springboot项目打jar包的方法
    JavaScript系列之获取变量数据类型
  • 原文地址:https://blog.csdn.net/hza163/article/details/127924225