27类和对象---继承与派生
1、继承:新建的类(称为子类)可以继承一个或多个父类(称为父类或超类),子类会继承父类的属性,从而解决代码重用问题。
Object类是所有python的基类,它提供了一些常用的方法(如__str__)的实现。
继承的功能: 1、通过继承实现代码重用
2、通过接口实现归一化设计
python3中都是新式类
python2中继承了object的是新式类,新式类与经典类的区别在继承顺序的区别、类实例类型的区别
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类,从左至右 pass # 查看继承 print(SubClass1.__base__) #只查看从左到右继承的第一个类 print(SubClass2.__bases__)#所有继承的父类,(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
2、使用继承来重用代码
派生:子类也可以添加自己新的属性或者在自己这里重新定义这些属性
class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f2') self.f1() class Bar(Foo): def f1(self): #派生,定义自己的属性 print('Bar.f1。。。') b=Bar() b.f2() # 继承,类的属性查找其实和函数的差不多,找f1()的时候还是先在bar()的作用域里
3、组合和继承
(1)继承的方式
通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人
(2)组合的方式
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,
教授教python和linux课程,教授有学生s1、s2、s3...
当类之间有显著不同,并且较小的类是较大的类的组成部分时,用组合较好
class People: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class Course: def __init__(self, name, period, price): self.name = name self.period = period self.price = price def tell_info(self): print('{}:{}:{}'.format(self.name, self.period, self.price)) class Teacher(People): def __init__(self, name, age, sex, job_title): People.__init__(self, name, age, sex) self.job_title = job_title self.course = [] self.students = [] class Student(People): def __init__(self, name, age, sex): People.__init__(self, name, age, sex) self.course = [] egon = Teacher('egon',19,'male','0001') min = Teacher('min',33,'female','0002') python = Course('python','3mons',30000) java = Course('java', '4mons',40000) s1 = Student('cc',19,'male') s2 = Student('cc2',19,'male') s3 = Student('cc3',19,'male') s4 = Student('cc4',19,'male') egon.course.append(python) egon.course.append(java) min.students.append(s1) min.students.append(s2) s1.course.append(python) for c in egon.course: c.tell_info()
4、接口与归一化设计
基于一个接口实现类,那么所有这些类产生的对象在使用时,从用法上来说都是一样的
归一化让使用者无需关心对象的类是什么,只需要知道这些对象具备哪些功能就可以了
# 模仿interface class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。 def read(self): #定接口函数read pass def write(self): #定义接口函数write pass class Txt(Interface): #文本,具体实现read和write def read(self): print('文本数据的读取方法') def write(self): print('文本数据的读取方法') class Sata(Interface): #磁盘,具体实现read和write def read(self): print('硬盘数据的读取方法') def write(self): print('硬盘数据的读取方法') class Process(Interface): def read(self): print('进程数据的读取方法') def write(self): print('进程数据的读取方法') # 只是像,但子类可以不用实现,这就用到了抽象类
5、抽象类
借助模块的实现,只能被继承, 不能被实例化,而且子类必须实现抽象方法
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),
而接口只强调函数属性的相似性。
import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type = 'file' @abc.abstractclassmethod #定义抽象方法,不用实现 def read(self): pass @abc.abstractclassmethod def write(self): pass # 子类继承,必须定义父类的两个方法,否则报错 class Txt(All_file): def read(self): print('Txt read....') def write(self): print('Txt write....')
6、继承顺序:新式类:广度优先
经典类:深度优先
可以通过类.__mro__查看
三条准则:1、子类会先于父类检查
2、多个父类会根据它们在列表中顺序检查
3、如果对下一个类存在两个合法的选择,那么选择第一个父类
7、子类中调用父类的方法
方法一:指名道姓,即父类名.父类方法()
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)#在子类中调用父类方法,直接用父类.方法() line1 = Subway('df',1000,'1000人','电','1号线') line1.run()
方法二:super().父类方法()
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): super().__init__(name, speed, load, power) self.line = line def run(self): print('{}欢迎你'.format(self.line)) # 在py3中,super()====>super(Subway,self) super().run() line1 = Subway('df',1000,'1000人','电','1号线') line1.run()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】