06_03、面向对象的特征二:继承
一、继承
1. 什么是继承?
继承就是新建类的一种方式,新建出来的类称为子类或者叫派生类,被继承的类称为父类或者基类
子类可以遗产父类的属性
2. 为什么要用继承?
类解决了对象与对象之间的代码冗余问题
继承解决类与类之间的代码冗余问题
3. 怎么用继承?
经典类:没有继承object类的子子孙孙类都是经典类
新式类:继承了object类的子子孙孙类都是新式类
'''只有在python2中才区分经典类和新式类,在python3中默认都是新式类'''
class People(): school = 'SH' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class Student(People): def __init__(self, name, age, gender, course=None): if course is None: course = [] People.__init__(self, name, age, gender) # 指名道姓的调用 self.course = course def choose_course(self): print('aaaa') class Teacher(People): def __init__(self, name, age, gender, level): People.__init__(self, name, age, gender) self.level = level def score(self): print('打分') stu = Student('tom', 19, 'male') tea = Teacher('ly', 20 ,'female', 10) print(stu.name) print(stu.school) print(tea.school)
二、单继承下的属性查找顺序
单继承下属性查找的顺序:
先在对象自己的名称空间中查找,再去产生对象的类中查找,再去继承的类中查找
例题1
1 class Foo: 2 def f1(self): 3 print('from Foo.f1') 4 5 def f2(self): 6 print('from Foo.f2') 7 self.f1() 8 9 10 class Bar(Foo): 11 def f1(self): 12 print('from Bar.f1') 13 14 15 obj = Bar() 16 obj.f2() 17 18 # from Foo.f2 19 # from Bar.f1
例题2
# 隐藏属性后的单继承条件下的属性查找
class Foo: def __f1(self): # _Foo__f1() print('from Foo.f1') def f2(self): print('from Foo.f2') self.__f1() # _Foo__f1() class Bar(Foo): def __f1(self): # _Bar__f1() print('from Bar.f1') obj = Bar() obj.f2() # from Foo.f2 # from Foo.f1
三、多继承下的属性查找顺序
经典类:深度优先查询
新式类:广度优先查询
四、super和mro列表
1、super介绍
super是调用父类属性的一种方法,另一种方式是指名道姓的调用
调用super()会得到一个特殊的对象,该对象专门用来引用父类的属性,且严格按照MRO规定的顺序向后查找
注意在Python2中super的使用需要完整地写成super(自己的类名,self) ,而在python3中可以简写为super()
这两种方式的区别是:
指名道姓调用是跟继承没有关系的
super()是依赖于继承的,并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
2、MRO列表介绍
MRO列表就是一个简单的所有基类的线性顺序列表
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。
它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
class People(): # 父类 school = 'SH' # 自定义对象属性 def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class Student(People): # 子类 # 自定义对象属性 def __init__(self, name, age, gender, course=None): if course is None: course = [] # 调用父类方式一:通过people指名道姓的调用 # People.__init__(self, name, age, gender) # 指名道姓的调用 # 调用父类方式二:通过super调用 # super(Student, self) super方法,返回的是一个特殊的对象 # 注意super在python2和python3中的不同用法 # super(Student, self).__init__(name, age, gender) # python2中的写法 super().__init__(name, age, gender) # python3中的写法 self.course = course def choose_course(self): # 模拟选课方法 print('aaaa') stu = Student('tom', 19, 'male') # 实例化对象 print(stu.school) # SH # 结果SH继承自父类people的school
五、组合
在一个类中以另外一个类的对象作为数据属性,称为类的组合。
组合与继承都是用来解决代码的重用性问题。
不同的是:
继承是一种“是”的关系,比如老师是人、学生是人,当类之间有很多相同的之处,应该使用继承;
而组合则是一种“有”的关系,比如老师有生日,老师有多门课程,
所以,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,应该使用组合
# 课程类 class Course: def __init__(self, name, period, price): self.name = name self.period = period self.price = price def tell_info(self): print('<%s %s %s>' % (self.name, self.period, self.price)) # 日期类 class Date: def __init__(self, year, mon, day): self.year = year self.mon = mon self.day = day def tell_birth(self): print('<%s-%s-%s>' % (self.year, self.mon, self.day)) # 人类 class People: school = '清华大学' def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age # Teacher类基于继承来重用People的代码,基于组合来重用Date类和Course类的代码 class Teacher(People): # 老师是人 def __init__(self, name, sex, age, title, year, mon, day): super().__init__(name, age, sex) # 利用super继承父类People的属性 self.birth = Date(year, mon, day) # 老师有生日,组合 self.courses = [] # 老师有课程,可以在实例化后,往该列表中添加Course类的对象,组合 def teach(self): print('%s is teaching' % self.name) python = Course('python', '3mons', 3000.0) # 实例化Course为python对象 linux = Course('linux', '5mons', 5000.0) # 实例化Course为linux对象 teacher1 = Teacher('lili', 'female', 28, '博士生导师', 1990, 3, 23) # 实例化Teacher为teacher1对象 # teacher1有两门课程 teacher1.courses.append(python) teacher1.courses.append(linux) # 重用Date类的功能 teacher1.birth.tell_birth() # 重用Course类的功能 for obj in teacher1.courses: obj.tell_info()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通