day15 课程(继承 & 单继承 & 多继承 & 重写 & 继承关系mro & 多层继承 & super & 私有属性及方法)
课程:https://www.bilibili.com/video/BV1o4411M71o?spm_id_from=333.788.videopod.episodes&p=292
15.1 了解继承
15.1.1 目标
继承的概念
单继承
多继承
子类重写父类的同名属性和方法
子类调用父类的同名属性和方法
多层继承
super()
私有属性和私有方法
15.1.2 继承的概念
生活中的继承,一般指的是子女继承父辈的财产
两个类存在父子集的继承关系,子类即使没有任何属性和方法,用子类创建的对象,此对象也将拥有父类中所有的属性和方法的使用权
好处:减少了代码量
15.2 扩展经典类和新式类
扩展1:经典类或旧式类
不由任意内置类型派生出的类,称之为经典类,python 2.xx 版本
# 经典类 class 类名: 代码 ......
扩展2:新式类
由内置类型派生出的类,默认继承 object ,顶级父类,也叫基类,python 3.xx 版本以上
# 新式类 class 类名(object): 代码 ......
15.3 体验继承
Python 面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:
# 1.定义父类 class A(object): # 继承 object 顶级父类, 不写也是默认 def __init__(self): self.num = 1 # 实例属性 def info_print(self): print(self.num) # 实例方法 # 2.定义子类 继承父类 class B(A): # 继承 A 类 pass # 只有一个占位符, B 类本身没有属性和方法 # 3.创建对象 result = B() # 基于 B类 创建 对象 result.info_print() # 1.对象可以调用方法,会自动补全 2.用 B类创建的对象可以调用 A类 的属性和方法, 即 B类继承了 A类的属性和方法 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day15\01.体验继承.py 1 Process finished with exit code 0
在 Python 中,所有类默认继承 object 类,object 类是顶级类或基类,其他子类叫做派生类
15.4 单继承
故事主线:一个煎饼果子老师傅,在煎饼果子界摸爬滚打多年,研发了一套精湛的摊煎饼果子技术,师父要把这套技术传授给他唯一的徒弟
分析:徒弟是不是要继承师父的所有技术?
# 1.师父类 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.徒弟类 class Prentice(Master): # 继承师父类 Master pass # 3.创建对象 daqiu = Prentice() # 基于徒弟类创建的对象 print(daqiu.kongfu) # 徒弟类对象拥有师父类的属性 daqiu.make_cake() # 徒弟类对象拥有师父类的方法 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day15\02.单继承.py ['古法煎饼果子配方'] 运用 ['古法煎饼果子配方'] 制作煎饼果子 Process finished with exit code 0
15.5 多继承
故事推进:daqiu 是个爱学习的好孩子,想学习更多的煎饼果子技术,于是,在百度搜索到黑马程序员,报班学习煎饼果子技术
所谓多继承意思就是一个类同时继承了多个父类
# 1.师父类 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 3.学校类 class School(object): def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.徒弟类 class Prentice1(School, Master): # 先继承 学校类 再继承 师父类 pass class Prentice2(Master, School): # 先继承 师父类 再继承 学校类 pass # 4.创建对象 daqiu1 = Prentice1() # 基于徒弟类中先继承 学校类 再继承师父类的对象 print(daqiu1.kongfu) # 学校类拥有的属性 ['黑马煎饼果子配方'] daqiu1.make_cake() # 学校类拥有的方法 运用 ['黑马煎饼果子配方'] 制作煎饼果子 print("------------------------------") daqiu2 = Prentice2() # 基于徒弟类中先继承 师父类 再继承学校类的对象 print(daqiu2.kongfu) # 师父类拥有的属性 ['古法煎饼果子配方'] daqiu2.make_cake() # 师父类拥有的方法 运用 ['古法煎饼果子配方'] 制作煎饼果子 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day15\03.多继承.py ['黑马煎饼果子配方'] 运用 ['黑马煎饼果子配方'] 制作煎饼果子 ------------------------------ ['古法煎饼果子配方'] 运用 ['古法煎饼果子配方'] 制作煎饼果子 Process finished with exit code 0
注意:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法
15.6 子类重写父类同名属性和方法
故事:daqiu 掌握了师父和培训的技术后,自己潜心钻研出自己的独门配方的一套全新的煎饼果子技术
# 1.师父类 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 3.学校类 class School(object): def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.徒弟类 徒弟类增加与父类的同名属性和方法 class Prentice(School, Master): def __init__(self): self.kongfu = ["独创煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 4.创建对象 daqiu = Prentice() # 基于徒弟类创建对象 print(daqiu.kongfu) # 使用徒弟类本身的属性 ['独创煎饼果子配方'] daqiu.make_cake() # 使用徒弟类本身的方法 运用 ['独创煎饼果子配方'] 制作煎饼果子 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day15\04.子类重写父类同名属性和方法.py ['独创煎饼果子配方'] 运用 ['独创煎饼果子配方'] 制作煎饼果子 Process finished with exit code 0
结论:如果子类和父类拥有同名属性和方法,子类创建对象调用属性和方法的时候,调用到的是子类里面的同名属性和方法
15.7 扩展__mro__继承层级
# 语法 print(类名.__mro__) # 返回元组 print(类名.mro()) # 返回列表
# 1.师父类 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.徒弟类 class Prentice(Master): # 继承师父类 Master pass # 3.创建对象 daqiu = Prentice() # 基于徒弟类创建的对象 print(daqiu.kongfu) # 徒弟类对象拥有的属性 daqiu.make_cake() # 徒弟类对象拥有的方法 # 打印当前的类继承的类有哪些及层级关系 print(Prentice.__mro__) # 学生继承的类及层级 元组 (<class '__main__.Prentice'>, <class '__main__.Master'>, <class 'object'>) print(Prentice.mro()) # 列表 [<class '__main__.Prentice'>, <class '__main__.Master'>, <class 'object'>] print(Master.mro()) # 老师继承的类 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day15\05.扩展_mro顺序.py ['古法煎饼果子配方'] 运用 ['古法煎饼果子配方'] 制作煎饼果子 (<class '__main__.Prentice'>, <class '__main__.Master'>, <class 'object'>) [<class '__main__.Prentice'>, <class '__main__.Master'>, <class 'object'>] [<class '__main__.Master'>, <class 'object'>] Process finished with exit code 0
15.8 子类调用父类同名方法和属性之思路分析
故事:很多顾客都希望也能吃到 古法 和 黑马 配方的煎饼果子
答:在徒弟类中分别再次封装函数,分别调用各自父类中的同名属性和方法,1.注意会有覆盖的情况,就近原则?2.函数中填 self,调用对象的属性和方法能传入 self
15.9 子类调用父类同名方法和属性之代码实现
注意:调用父类同名方法需要再调用自己的初始化,让自己类中的属性生效,否则将使用类中默认属性或最后一次调用的属性
# 1.师父类 属性和方法 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.学校类 属性和方法 class School(object): def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 3.徒弟继承师父和学校, 同时自己独创属性和方法后仍可以调用师父和学校的同名属性和方法 class Prentice(School, Master): def __init__(self): self.kongfu = ["独创煎饼果子配方"] # 属性 def make_cake(self): self.__init__() # 这里要再次调用自己的属性函数, 当前类中与继承类有同名属性 kongfu, 当基于类创建对象, 若其他类先调用 kongfu 这个属性,这个值就会被覆盖(可以理解为变量被重新赋值,赋值的结果永远是最后赋值的生效) print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # self 需要接收调用自己的对象 def make_master_cake(self): # 再次封装师父类的函数 Master.__init__(self) # 再次封装后, 调用方法前先调用自己属性的函数, 否则对象中使用 hongfu 前一个的同名属性 Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) daqiu = Prentice() daqiu.make_master_cake() # 古法 daqiu.make_school_cake() # 黑马 daqiu.make_cake() # 独创, 这里如果没有 init, 将会是 黑马, 因为 make_cake 中使用的 hongfu 将会是黑马 init 后的属性值 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day15\06.子类调用父类同名方法和属性之代码实现.py 运用 ['古法煎饼果子配方'] 制作煎饼果子 运用 ['黑马煎饼果子配方'] 制作煎饼果子 运用 ['独创煎饼果子配方'] 制作煎饼果子 Process finished with exit code 0
15.10 多层继承
故事:N年后,daqiu 老了,想要把所有技术传承给自己的徒弟
# 1.师父类 属性和方法 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.学校类 属性和方法 class School(object): def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 3.徒弟继承师父和学校, 同时自己独创属性和方法后仍可以调用师父和学校的同名属性和方法 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) # 4.徒孙类 继承 daqiu 的所有技术 class Tusun(Prentice): pass xiaoqiu = Tusun() xiaoqiu.make_master_cake() # 师父的师父的技术 xiaoqiu.make_school_cake() # 师父在学校学习的技术 xiaoqiu.make_cake() ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day15\07.多层继承.py 运用 ['古法煎饼果子配方'] 制作煎饼果子 运用 ['黑马煎饼果子配方'] 制作煎饼果子 运用 ['独创煎饼果子配方'] 制作煎饼果子 Process finished with exit code 0
15.11 super()方法作用
super():调用父类方法
注意:使用 super() 可以自动查找父类,调用顺序遵循 __mro__ 类属性的顺序,比较适合单继承使用
# 1.师父类 属性和方法 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.学校类 属性和方法 class School(object): def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 3.徒弟继承师父和学校, 同时自己独创属性和方法后仍可以调用师父和学校的同名属性和方法 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) # 3.1 可以一次性调用父类 School, Master 的方法 def make_old_cake(self): # 方法一: 弊端: 1.School, Master 是类名, 上面定义的类名修改, 下面也需要修改 # 2.当调用的父类越多, 代码量越大,且都是冗余的代码 Master.__init__(self) Master.make_cake(self) School.__init__(self) School.make_cake(self) daqiu = Prentice() daqiu.make_old_cake() # 古法 & 黑马 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe "D:\Pycharm\code\day15\08.super()方法.py" 运用 ['古法煎饼果子配方'] 制作煎饼果子 运用 ['黑马煎饼果子配方'] 制作煎饼果子 Process finished with exit code 0
15.12 super()方法写法
15.12.1 语法
# 语法 super(当前类名, self).函数() super().函数()
15.12.2 快速体验带参数
# 1.师父类 属性和方法 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.学校类 属性和方法 class School(Master): # 2.1 修改继承关系 def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.1 super() 带参数的写法 super(School, self).__init__() super(School, self).make_cake() # 3.徒弟继承师父和学校, 同时自己独创属性和方法后仍可以调用师父和学校的同名属性和方法 class Prentice(School): 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) # 3.1 可以一次性调用父类 School, Master 的方法 def make_old_cake(self): # 方法一: 弊端: 1.School, Master 是类名, 上面定义的类名修改, 下面也需要修改 # 2.当调用的父类越来, 代码量越大 # Master.__init__(self) # Master.make_cake(self) # School.__init__(self) # School.make_cake(self) # 方法二: 2.1 弊端: super 有本身类名, 本身类名更改, super 中类名也需要更改 super(Prentice, self).__init__() super(Prentice, self).make_cake() daqiu = Prentice() daqiu.make_old_cake() # 古法 & 黑马 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe "D:\Pycharm\code\day15\08.super()方法.py" 运用 ['黑马煎饼果子配方'] 制作煎饼果子 运用 ['古法煎饼果子配方'] 制作煎饼果子 Process finished with exit code 0
15.12.3 快速体验无参数
# 1.师父类 属性和方法 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.学校类 属性和方法 class School(Master): # 2.1 修改继承关系 def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.1 super() 带参数的写法 # super(School, self).__init__() # super(School, self).make_cake() # 2.2 super() 无参数的写法 super().__init__() super().make_cake() # 3.徒弟继承师父和学校, 同时自己独创属性和方法后仍可以调用师父和学校的同名属性和方法 class Prentice(School): 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) # 3.1 可以一次性调用父类 School, Master 的方法 def make_old_cake(self): # 方法一: 弊端: 1.School, Master 是类名, 上面定义的类名修改, 下面也需要修改 # 2.当调用的父类越来, 代码量越大 # Master.__init__(self) # Master.make_cake(self) # School.__init__(self) # School.make_cake(self) # 方法二: 2.1 弊端: 本身有 super 有本身类名, 本身类名更改, super 中类名也需要更改 # super(Prentice, self).__init__() # super(Prentice, self).make_cake() # 方法二: 2.2 无参数 super().__init__() super().make_cake() daqiu = Prentice() daqiu.make_old_cake() # 古法 & 黑马 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe "D:\Pycharm\code\day15\08.super()方法.py" 运用 ['黑马煎饼果子配方'] 制作煎饼果子 运用 ['古法煎饼果子配方'] 制作煎饼果子 Process finished with exit code 0
15.13 定义私有属性和方法
在 Python 中,默认是公有属性和公有方法,会继承给子类,也可以为实例属性和实例方法设置私有权限,即设置某个实例属性或实例方法不继承给子类
设置私有权限的方法:在属性名和方法名 前面加上两个下划线 __属性名、__方法名
故事:daqiu 把技术传承给徒弟的同时,不想把自己的钱继承给徒弟,这个时候就要把 钱 这个实例属性设置为私有权限
# 1.师父类 属性和方法 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.学校类 属性和方法 class School(object): def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 3.徒弟继承师父和学校 class Prentice(School, Master): def __init__(self): self.kongfu = ["独创煎饼果子配方"] # 属性 self.__money = 200000 # 定义私有属性 def __info_print(self): # 定义私有方法 print(self.kongfu) print(self.__money) 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) # 4.徒孙类 继承 daqiu 的所有技术 class Tusun(Prentice): pass daqiu = Prentice() # 私有属性和方法, 通过继承没办法获得 # print(daqiu.__money) # 报错: AttributeError: 'Prentice' object has no attribute '__money' # daqiu.__info_print() # 报错: AttributeError: 'Prentice' object has no attribute '__info_print' xiaoqiu = Tusun() # print(xiaoqiu.__money) # 报错: AttributeError: 'Tusun' object has no attribute '__money' # xiaoqiu.__info_print() # 报错: AttributeError: 'Tusun' object has no attribute '__info_print'
15.14 获取和修改私有属性值
在 Python 中,一般定义函数名 get_xx 用来获取私有属性,定义 set_xx 用来修改私有属性值( get 和 set 定义方式是工作习惯)
# 1.师父类 属性和方法 class Master(object): def __init__(self): self.kongfu = ["古法煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 2.学校类 属性和方法 class School(object): def __init__(self): self.kongfu = ["黑马煎饼果子配方"] # 属性 def make_cake(self): print(f"运用 {self.kongfu} 制作煎饼果子") # 方法 # 3.徒弟继承师父和学校 class Prentice(School, Master): def __init__(self): self.kongfu = ["独创煎饼果子配方"] # 属性 self.__money = 200000 # 定义私有属性 def __info_print(self): # 定义私有方法 print(self.kongfu) print(self.__money) 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) # 定义函数: 获取私有属性值 get_xx def get_money(self): return self.__money # 定义函数: 修改私有属性值 set_xx def set_money(self, money): # 传参修改 self.__money = money # 4.徒孙类 继承 daqiu 的所有技术 class Tusun(Prentice): pass daqiu = Prentice() # 私有属性和方法, 通过继承没办法获得 print(daqiu.get_money()) # 自己可以获取 daqiu.set_money(10) # 自己可以修改 print(daqiu.get_money()) print("---------------------") xiaoqiu = Tusun() # 被继承 print(xiaoqiu.get_money()) # 可以获取 xiaoqiu.set_money(666) # 可以修改 print(xiaoqiu.get_money()) ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day15\10.获取和修改私有属性值.py 200000 10 --------------------- 200000 666 Process finished with exit code 0
15.15 继承总结
1.继承的特点
(1)子类默认拥有父类的所有属性和方法
(2)子类重写父类同名方法和属性(子类和父类同名属性和方法,调用的是子类里面的)
(3)子类调用父类同名方法和属性(父类类名.属性和方法、super)
2.super() 方法快速调用父类方法
3.私有权限
(1)不能继承给子类的属性和方法需要添加私有权限
(2)语法
class 类名(): __属性名 = 值 # 私有属性 def __函数名(self): # 私有方法 代码 ......
4.获取私有权限
class 类名(): # 定义函数: 获取私有属性值 get_xx def get_函数名(self): return 私有属性 # 定义函数: 修改私有属性值 set_xx def set_函数名(self): self.__属性值 = 新属性值
———————————————————————————————————————————————————————————————————————————
无敌小马爱学习