外观
第二章 面向对象高级
- 定义类的几种语法
- Python中的继承
- Python中的封装
- Python中的多态
- 面向对象的其他特性
1. 定义类的几种语法
- 方法1:类名
- 方法2:类名()
- 方法3:类名(object) 最常用的方式
2. Inheritance
在Python中,所有类默认继承object类,object类是顶级类或基类,其他子类叫派生类。 当子类继承父类时,子类拥有和父类完全一样的功能,但是不用再写大量重复代码。
- 优势:提高代码复用率,减少重复代码的书写。
- 弊端:耦合性增强,父类不好的部分子类都会有。
- 开发原则:高内聚,低耦合。内聚:类自己处理问题的能力;耦合:类与类之间的关系。
2.1 单继承
一个子类只能继承一个父类,不能继承多个类。这个子类有父类的属性和方法。
2.2 多继承
一个类同时继承多个父类,并且同时具有所有父类的属性和方法。
- 注意:当一个类有多个父类时,默认继承第一个父类的同名属性和方法,可以使用 class.__mro__attribute 或 class.mro() 的方法查看调用的先后顺序。
- MRO: method resolution order 方法解析顺序
# 查看mro机制的结果
print(Prentice.mro()) # Prentice -> School -> Master -> object
print(Prentice.__mro__)
"""
[<class '__main__.Prentice'>, <class '__main__.Master'>, <class '__main__.Training'>, <class 'object'>]
(<class '__main__.Prentice'>, <class '__main__.Master'>, <class '__main__.Training'>, <class 'object'>)
"""2.3 Override
重写=覆盖,子类属性或方法与父类命名相同时,父类继承下来的成员可以重新定义.
2.4 子类调用父类方法
- 子类想保留父类的行为,则需要在子类中调用父类方法,可以直接使用父类名在调用,使用方法:
parent.parentmethod(self) - 使用
super()调用父类方法,使用的方法:super().parentmethod()- 使用
super()可以自动查找父类,适合单继承使用,多继承不建议
- 使用
2.5 多层继承
C继承B,B继承A这种结构的多层继承关系。
3. Encapsulation
在软件编程中,将属性和方法书写到类的里面的操作。封装可以为属性和方法添加私有权限。
- 优势:安全性、复用性
- 弊端:代码量显著增加
在Python中可以为属性和方法设置私有权限,即设置某个属性或方法不继承给子类。设置私有属性和方法的方式:在属性或方法名前加__,格式:
# private attribute
__attribute
# private method
def __method():私有属性和方法使用规则:
- 只能在类的内部使用,不能在外部使用;
- 如果想在类外部使用,通过公共接口。
3.1 私有属性
不用继承给子类的属性被称为私有属性,在属性或方法名前加上__,就可以设置私有属性或方法。
3.2 私有方法
私有属性不能直接访问,在Python中,一般定义方法名get__attribute用来获取私有属性,定义set__attribute用来修改私有属性值。
4. Polymorphism
同一个函数,传入不同的对象,得到不同的状态。
- 优势:应用解耦,同函数不同效果
- 弊端:无法精准限定类型
4.1 成立条件
python 是伪多态,即便都没有实现,系统也不会报错。
- 有继承(定义父类、定义子类,子类继承父类)
- 函数重写(子类重写父类函数)
- 父类引用指向子类对象(子类对象传给父类对象调用者)
python
构建对象对战平台object_play
1 英雄一代机(战力60)与敌军栈机(战力70)对抗。英雄一代栈机失败!
2 卧薪尝胆,英雄二代机(战力80)出场,战胜敌军战机!
3 对象对战平台 object_play,代码不变,完成多次战斗
思路分析
抽象战机类 HeroFighter, AdvHeroFighter;敌方战机 EnemyFighter
构建对象战斗平台,使用多态实现4.2 优势
- 在不改变框架代码的情况下,通过多态语法轻松实现模块与模块之间的解耦合,实现了软件系统的可拓展性;
- 解耦合:搭建平台函数相当于任务的调用者,子类、孙子类重写父类函数,相当于子任务,即任务的调用者和任务的编写者进行解耦合;
- 可拓展:搭建的平台函数可以在不做任何修改的情况下,调用之后工程师写的代码。
4.3 抽象类
父类用来确定有哪些方法(父类指定接口标准),具体的方法实现由子类实现(子类实现接口标准),这种写法属于抽象类。
- 抽象类:含有抽象方法的类
- 抽象方法:方法体是空实现,即
pass的称之为抽象方法 - abstract class = interface = standard
配合多态,可以完成:
- 抽象的父类设计(设计标准)
- 具体的子类实现(实现标准 )
5. 面向对象的其他特性
5.1 对象属性
属性:类或对象中定义的属性。object.attribute 和 self.sttribute
5.2 类属性
类所拥有的属性,它能被整个类共享(即可以直接调用)。
python
Class.attribute # 推荐使用
object.attribute5.3 类方法
类所拥有的方法,并需要使用装饰器 @classmethod 来标识其为类方法,同时一定要注意的是对于类方法的第一个参数必须是类对象,通常以cls作为第一个参数名。
5.4 静态方法
需要通过装饰器 @staticmethod 来标识其为静态方法,且静态方法不需要定义参数。
6. Python综合案例:学生信息管理系统
6.1 需求分析
开始 -》总程序入口 -》显示操作界面(添加,修改,删除,查询,显示所有,保存信息,退出系统) -》结束
- 使用面向对象、字符串、列表、字典、文件等知识点来完成一个学生管理系统V2.0;
- 可以显示基本的版本信息和操作界面;
- 可以通过键盘输入信息来完成基本功能,例如选择序号、确认退出、添加学生、修改信息等;
- 学生属性姓名有姓名、性别、年龄、联系方式、描述信息等;
- 使用系统可对学生信息进行增删改查;
- 可以使用文件对学生信息进行加载或保存等;
- 可重复对学生进行增删改查操作,当确认退出系统后,直接退出系统;
- 请使用面向对象编程思想完成项目的升级处理;
- 针对学生,该系统具有添加、修改、删除、查询所有学生/单个学生、保存信息、退出系统等操作;
- 角色分析
- 角色1:学生管理系统 Student
- 角色2:学生管理系统 StudentCMS(content management system)
- 注意:为了方便维护代码,一个角色一个文件,项目的程序主入口,习惯为
main.py
- 项目文件规划
- 创建项目目录,例如
StudentManagerSystem程序文件如下:- 程序入口文件:
main.py - 学生文件:
student.py - 管理系统文件:
studentcms.py
- 程序入口文件:
- 创建项目目录,例如
6.2 开发实践
一. 学生类文件:student.py
二. 学生管理系统文件:studentcms.py
- 创建学生管理系统类
- 存储数据的形式:列表存储学生对象
- 显示界面
- 系统功能
- 添加学生信息
- 删除学生信息
- 修改学生信息
- 查询学生信息
- 显示所有学生信息
- 保存学生信息
- 退出系统
- 搭建项目基本框架:为了便于后期快速开发,一般在项目初期会根据项目开发需求进行搭建基本项目框架,以便更高效开发。
- 需求:系统功能循环使用,用户输入不同的功能序号执行不同功能。
- 步骤:
- 定义程序入口函数
start():- 模拟系统启动用户等待
- 显示功能菜单
- 用户输入功能序号
- 根据用户输入的功能序号执行不同功能,同时考虑程序稳定性
- 定义系统功能函数,添加、删除学生等
- 退出系统:退出前必须要能反复多次显示操作界面
- 能反复多次的选择操作序号来执行功能;
- 用户想退出时,可以输入
y或Y后退出系统的继续执行。
三. 程序主入口文件:main.py
6.3 具体实现代码
6.3.1 添加学生信息
python
# 1.添加学生信息
def add_student(self):
name = input('input student name: ')
gender = input('input student gender: ')
age = input('input student age: ')
phone = int(input('input student phone: '))
desc = input('input student description: ')
# 把上述信息封装成学生对象
stu = Student(name, gender, age, phone, desc)
self.stu_list.append(stu)
print(f'add {name} student info successfully\n')6.3.2 修改学生信息
python
# 2.用户输入目标学生姓名,cms遍历学生数据列表。
# 如果用户输入的学生姓名存在,则修改该学生其他信息,否则提示该学生不存在。
def modify_student(self):
mod_name = input('input student name you want to modify: ')
for stu in self.stu_list:
if stu.name == mod_name:
# 提示用户录入新的学生信息
print(f'Now you can input new info about {mod_name}!')
stu.gender = input('input modified student gender: ')
stu.age = int(input('input modified student age: '))
stu.phone = int(input('input modified student phone: '))
stu.desc = input('input modified student description: ')
print(f'Modified {mod_name} student info successfully\n')
break
else:
print(f'{mod_name} student info did not found, please check the info first!\n')6.3.3 删除学生信息
python
# 3.用户输入目标学生姓名,cms遍历学生数据列表
# 如果用户输入的学生姓名存在,则删除,否则提示该学生不存在。
def delete_student(self):
del_name = input('input student name you want to delete: ')
for stu in self.stu_list:
if stu.name == del_name:
self.stu_list.remove(stu)
print(f'remove {del_name} student info successfully\n')
break
else:
print(f'{del_name} student info did not found.\n')6.3.4 查询学生信息
python
# 4.用户输入目标学生姓名,cms遍历学生数据列表。
# 如果用户输入的学生姓名存在,则打印学生信息,否则提示该学生不存在。
def query_particular_student(self):
query_name = input('input student name you want to query: ')
for stu in self.stu_list:
if stu.name == query_name:
print(stu, end='\n')
break
else:
print(f'{query_name} student info did not found.\n')6.3.5 显示所有学生信息
python
# 5. 显示所有学生信息,便于浏览:遍历学生数据列表并打印所有信息
def show_student(self):
# 5.1. 判断列表长度,如果长度为0,需要提示:暂无学生信息
length_list = len(self.stu_list)
if length_list == 0:
print('no student info, please add student information first!\n')
# 5.2. 如果长度不为0,遍历并打印所有学生信息
for stu in self.stu_list:
print(stu)
print()6.3.6 保存信息
python
# 6. 保存学生信息:将修改以后的学生数据保存到存储数据的文件
# 步骤:打开文件 -> 将列表中的学生转换为String类型写入文件 -> 关闭文件
def save_student(self):
# 关联学生信息文件
with open('./stu_data.txt', 'w', encoding='utf-8') as dest_file:
# 把 [stu_object, stu_object, Stu_object] → [dic, dic, dic]
stu_dict = [stu.__dict__ for stu in self.stu_list]
# 把字典列表,持久化到文件中
dest_file.write(str(stu_dict)) # 务必转成字符串再写入,否则会报错
评论区
可以在这里补充理解、提问,或记录这一章的讨论。