当前位置: 首页 > news >正文

python进阶篇-day03-学生管理系统与深浅拷贝

day03-学生管理系统-面向对象

魔术方法: __ dict __将对象的属性和属性值封装为字典

用字典的值实例化对象: 对象名(**字典) => 拆包

student.py

"""
该文件记录的是: 学生类的信息.
​
学生的属性如下:姓名, 性别, 年龄, 联系方式, 描述信息
"""
​
# 1. 定义学生类.
class Student(object):# 2. 初始化学生信息def __init__(self, name, gender, age, mobile, des):"""该魔法方法用于 初始化 学生的属性信息.:param name: 姓名:param gender: 性别:param age: 年龄:param mobile: 手机号:param des: 描述信息"""self.name = nameself.gender = genderself.age = ageself.mobile = mobileself.des = des
​# 3. 打印学生信息.def __str__(self):# print(__name__)return f'姓名: {self.name}, 性别: {self.gender}, 年龄: {self.age}, 手机号: {self.mobile}, 描述信息: {self.des}'# return '姓名: %s, 性别: %s, 年龄: %d, 手机号: %s, 描述信息: %s' % (self.name, self.gender, self.age, self.mobile, self.des)
​
​
# 4. 记得在main函数中测试, 否则别人导入这个模块的时候, 会自动执行如下的测试代码.
if __name__ == '__main__':# 5. 创建学生对象.s = Student('乔峰', '男', 39, '13112345678', '丐帮帮主')# 6. 打印学生信息.print(s)

student_cms.py

"""
该文件记录的是: 学生管理系统类的信息.
​
名词 cms 解释:全称叫: Content Management System, 内容管理系统.
​
学生管理系统类 StudentCms属性:stu_info = [{学生信息}, {学生信息}...]即: stu_info = [学生对象, 学生对象...]行为: 函数__init__()      # 初始化属性信息show_view()     # 打印提示信息, 无需使用self对象, 所以设置为: 静态方法.add_student()   # 添加学生信息del_student()   # 删除学生信息update_student()   # 修改学生信息search_one_student()   # 查询单个学生信息search_all_student()   # 查询所有学生信息save_student()   # 保存学生信息 => 文件中, 存档.load_student()   # 从文件中 => 学生信息, 读档.start()   # 表示整体的业务逻辑 => 框架
"""
# 导包
import time
import os  # Operating System: 系统模块.
from student import Student
​
​
# 1. 定义学生管理系统类.
class StudentCms(object):# 2. 定义初始化属性.def __init__(self):# 格式: [{学生信息}, {学生信息}...],   即: [学生对象, 学生对象...]self.stu_info = []
​# 为了提高效率, 准备的测试数据# s1 = Student('乔峰', '男', 39, '131', '丐帮帮主')# s2 = Student('阿朱', '女', 35, '151', '丐帮帮主夫人')# s3 = Student('虚竹', '男', 31, '161', '灵鹫宫宫主')# s4 = Student('李清露', '女', 25, '171', '灵鹫宫宫主夫人')# self.stu_info = [s1, s2, s3, s4]
​# 3. show_view()     # 打印提示信息, 设置为: 静态方法.@staticmethoddef show_view():print("*" * 21)print("欢迎使用学生管理系统V2.0")print("\t1. 添加学生信息")print("\t2. 修改学生信息")print("\t3. 删除学生信息")print("\t4. 查询单个学生信息")print("\t5. 查询所有学生信息")print("\t6. 保存学生信息")print("\t7. 退出系统")print("*" * 21)
​# 4. add_student()   # 添加学生信息def add_student(self):# 4.1 提示用户录入学生信息 并接收.name = input('请录入学生的姓名: ')gender = input('请录入学生的性别: ')age = input('请录入学生的年龄: ')mobile = input('请录入学生的手机号: ')des = input('请录入学生的描述信息: ')# 4.2 将上述的信息封装成 学生对象.new_stu = Student(name, gender, age, mobile, des)# 4.3 将学生对象添加到列表中.self.stu_info.append(new_stu)# 4.4 打印提示信息.print(f"添加学生 {name} 的信息成功!\n")
​# 5. del_student()   # 删除学生信息def del_student(self):# 5.1 提示用户录入要删除的学生 姓名.      扩展: 假设存在重名学生, 都要删掉, 自己代码实现.del_name = input('请录入要删除的学生姓名: ')# 5.2 遍历学生列表, 获取每个学生信息.for stu in self.stu_info:# stu: 就是具体的每个学生对象.# 5.3 判断当前学生信息, 是否是 要删除的学生.if stu.name == del_name:# 5.4 走这里, 删除该学生对象即可.self.stu_info.remove(stu)print(f"删除学生 {del_name} 的信息成功!\n")breakelse:# 5.5 走这里, 说明没有找到要删除的学生.print(f'未找到 {del_name} 学生信息, 请校验后重新操作!\n')
​# 6. update_student()   # 修改学生信息def update_student(self):# 6.1 提示用户录入要修改的学生 姓名, 并接收.update_name = input('请录入要修改的学生姓名: ')# 6.2 遍历学生列表, 获取每个学生的信息.for stu in self.stu_info:# stu: 就是具体的每个学生对象.# 6.3 判断当前学生信息, 是否是 要修改的学生.if stu.name == update_name:# 6.4 走这里, 提示用户, 录入要修改的信息, 并修改当前学生的信息.stu.gender = input('请录入新的性别: ')stu.age = input('请录入新的年龄: ')stu.mobile = input('请录入新的手机号: ')stu.des = input('请录入新的描述信息: ')# 6.5 提示, 并结束.print(f"修改 {update_name} 的信息成功!\n")breakelse:# 6.6 走这里, 说明没有找到要修改的学生.print(f'未找到 {update_name} 学生信息, 请重新操作!\n')
​# 7. search_one_student()   # 查询单个学生信息def search_one_student(self):# 7.1 提示用户录入要查询的学生 姓名, 并接收.search_name = input('请录入要查询的学生姓名: ')# 7.2 遍历学生列表, 获取每个学生的信息.for stu in self.stu_info:# stu: 就是具体的每个学生对象.# 7.3 判断当前学生信息, 是否是 要查询的学生.if stu.name == search_name:# 7.4 走这里, 说明找到了, 打印即可.# print(stu, '\n')print(stu, end='\n\n')breakelse:# 7.5 走这里, 说明没有找到要修改的学生.print(f'未找到 {search_name} 学生信息, 请重新操作!\n')
​# 8. search_all_student()   # 查询所有学生信息def search_all_student(self):# 8.1 判断列表中是否有 学生信息.if len(self.stu_info) <= 0:# 8.2 走这里, 说明暂无学生信息.print('暂无学生信息, 请添加后重新查询!\n')else:# 8.3 走这里, 说明有学生信息, 遍历打印即可.for stu in self.stu_info:print(stu)print()  # 换行, 让格式更加好看.
​# 9. save_student()   # 保存学生信息 => 文件中, 存档.def save_student(self):# 9.1 把 学生对象列表 => 列表嵌套字典的形式, 即:  [学生对象, 学生对象...]    =>  [{学生信息}, {学生信息}...]stu_dict_list = [stu.__dict__ for stu in self.stu_info]# 9.2 把上述的学生信息(列表嵌套字典), 写到目的地文件 student.data 文件中.with open('./student.data', 'w', encoding='utf-8') as dest_f:  # dest: 目的地# 9.3 具体的写的动作.# 先把 列表嵌套字典, 转换成 字符串, 再写入到目的地文件中.dest_f.write(str(stu_dict_list))# 9.4 提示即可.print('学生信息存档成功!\n')
​# 10. load_student()   # 从文件中 => 学生信息, 读档.def load_student(self):# 10.1 判断数据源文件是否存在.if os.path.isfile('./student.data'):  # 判断 student.data 必须是 存在的 文件才行.# 10.2 走到这里, 说明源文件存在, 读取文件信息即可.with open('./student.data', 'r', encoding='utf-8') as src_f:# 10.3 具体的读取文件数据的操作.# 格式为:  "[{'name': '乔峰', 'gender': '男', 'age': 39, 'mobile': '131', 'des': '丐帮帮主'}, {学生信息}, {学生信息}...]"str_list_data = src_f.read()# 10.4 判断 字符串的长度是否合法, 如果不合法, 给个默认值.if len(str_list_data) <= 0:str_list_data = '[]'# 10.5 把上述的 字符串形式的 列表嵌套字典 => 列表嵌套字典 的格式.# 格式为: [{'name': '乔峰', 'gender': '男', 'age': 39, 'mobile': '131', 'des': '丐帮帮主'}, {学生信息}, {学生信息}...]list_data = eval(str_list_data)  # eval(): 去掉最外边的那组引号, 剩下的是啥就转成什么类型.# 10.6 把上述的列表嵌套字典形式的 学生数据 => 学生列表对象, 即: [学生对象, 学生对象...]self.stu_info = [Student(**stu_dict) for stu_dict in list_data]else:# 10.7 走这里, 说明文件不存在, 创建即可.# src_f = open('./student.data', 'w', encoding='utf-8')# src_f.close()
​# 扩展: 你去查一下 os模块中是否有直接创建文件的函数, 有可以直接使用它来完成需求.os.open('./student.data', flags=os.O_CREAT)  # 效果同上.
​# 11. start()   # 表示整体的业务逻辑 => 框架def start(self):# 11.0 加载学生的信息, 类似于: 读档.self.load_student()
​# 11.1 因为是重复操作的, 所以用 while(True) 死循环.while True:# 11.2 模拟用户等待time.sleep(1)  # 1秒# 11.3 打印提示信息# self.show_view()      # 静态方法, 调用方式1: 对象名.   可以, 但是不推荐.StudentCms.show_view()  # 静态方法, 调用方式1: 类名.     推荐
​# 11.4 提示用户录入他/她要操作的编号, 并接收.num = input('请录入您要操作的编号: ')# 11.5 基于用户录入的编号, 判断, 并进行对应的操作.if num == '1':# print("1. 添加学生信息")self.add_student()elif num == '2':# print("2. 修改学生信息")self.update_student()elif num == '3':# print("3. 删除学生信息")self.del_student()elif num == '4':# print("4. 查询单个学生信息")self.search_one_student()elif num == '5':# print("5. 查询所有学生信息")self.search_all_student()elif num == '6':# print("6. 保存学生信息")self.save_student()elif num == '7':# 细节: 退出系统, 给一个提示信息.result = input('您确定要退出吗, y(退出), 其它(继续) => ')if result.lower() == 'y':  # lower()函数: 把字母转成其对应的 小写形式.time.sleep(2)# 细节: 也可以考虑, 在退出之前(就是这里), 再次保存下学生信息.# self.save_student()print('感谢您的使用, 再见!')breakelse:print('录入有误, 请重新录入!\n')
​
​
# 12. 在main方法中测试.
if __name__ == '__main__':stu_cms = StudentCms()stu_cms.start()

main.py

"""
该文件记录的是: 学生管理系统的主入口
​
目前的文件student.py      => 存放 Student 学生类信息的student_cms.py  => 存放 StudentCms 学生管理系统类 信息的.
"""
​
# 导包
from student_cms import StudentCms
​
# 1. 制定程序的主入口
if __name__ == '__main__':# 2. 创建学生管理系统类 对象stu_cms = StudentCms()# 3. 启动程序.stu_cms.start()

深浅拷贝

回顾可变与不可变类型

划分依据

在不改变地址值的情况下, 是否可以修改内容, 可以 => 可变类型, 不可以 => 不可变类型.

代码

# 需求1: 演示不可变类型.
a = 10
print(f'a的值: {a}')           # 10
print(f'a的地址: {id(a)}')     # 0x01
# 修改不可变类型
a = 20
print(f'a的值: {a}')           # 20
print(f'a的地址: {id(a)}')     # 0x02
print('-' * 21)
​
​
# 需求2: 演示可变类型.
list1 = [1, 2, 3]
print(f'list1的值: {list1}')          # [1, 2, 3]
print(f'list1的地址: {id(list1)}')    # 0x03
# 修改可变类型
list1[1] = 200
print(f'list1的值: {list1}')          # [1, 200, 3]
print(f'list1的地址: {id(list1)}')    # 0x03
​

深浅拷贝介绍

  1. 所谓的深浅拷贝, 指的是: 拷贝的多与少. 深拷贝拷贝的多, 浅拷贝拷贝的少.

  2. 深浅拷贝都可以操作可变 和 不可变类型, 但是深浅拷贝一般不会操作不可变类型, 且你遇到的面试题几乎都是: 深浅拷贝操作可变类型.

  3. 回顾可变和不可变类型, 划分依据: 在不改变地址值的情况下, 是否可以修改内容, 可以 => 可变类型, 不可以 => 不可变类型.可变类型: 列表, 字典, 集合不可变类型: 字符串, 整数, 浮点型, 元组, 布尔...

  4. 所谓的深浅拷贝, 指的就是 copy 模块的不同函数.浅拷贝: copy.copy()深拷贝: copy.deepcopy()

代码演示

# 导包
import copy
​
# python的赋值操作属于引用赋值(eg:b是a的别名, 形参是实参的别名)
def dm01_普通赋值():
​# 1 python中的赋值操作, 属于引用赋值 (把a的地址赋值给b)# 2 b是a的别名, b和a都指向相同的内存空间a = 10b = aprint('id(a)-->', id(a))    # 0x01print('id(b)-->', id(b))    # 0x01print('id(10)-->', id(10))  # 0x01
​# 3 也是引用赋值 c和d指向相同的内存空间a = [1, 2, 3]b = [11, 22, 33]c = [a, b]d = cprint('id(c)-->', id(c))    # 0x03print('id(d)-->', id(d))    # 0x03
​# 4 值的方式赋值 a 指向一块内存空间、b 也指向一块内存空间# b = a python中不支持, 这样做传参效率高
​
​
# 浅拷贝可变类型: 只拷贝第1层数据, 深层次数据不拷贝
def dm02_浅拷贝可变类型():a = [1, 2, 3]b = [11, 22, 33]c = [6, 7, a, b]
​# 测试1 id(c)和id(d)d = copy.copy(c)        # 浅拷贝 = 只会拷贝 可变类型的 第1层数据.print('id(c)-->', id(c))    # 0x03print('id(d)-->', id(d))    # 0x04print("id(c)和id(d)值不一样, 说明浅拷贝第1层(最外面一层的数据)")
​# 测试2print(id(c[2]))     # 0x01print(id(a))        # 0x01print("id(c[2])和id(a)值一样, 说明浅拷贝第2层的数据")
​# 修改a[2] = 22a[2] = 22# c[0] = 100print('c->', c)     # [6, 7, [1, 2, 22], [11, 22, 33]]print('d->', d)     # [6, 7, [1, 2, 22], [11, 22, 33]]
​
​
# 浅拷贝不可变类型: 不会给拷贝的对象c开辟新的内存空间, 而只是拷贝了这个对象的引用
def dm03_浅拷贝不可变类型():
​# 不可变类型 a b ca = (1, 2, 3)b = (11, 22, 33)c = (6, 7, a, b)
​d = copy.copy(c)print('id(c)-->', id(c))    # 0x03print('id(d)-->', id(d))    # 0x03print("id(c)和id(d)值一样, 说明c和d指向相同的内存空间")
​
​
# 深拷贝可变类型: 若为可变类型开辟新的内存空间,所有层都会深拷贝
# 作用: 能保证数据的安全
def dm04_深拷贝可变类型():a = [1, 2, 3]b = [11, 22, 33]c = [6, 7, a, b]
​d = copy.deepcopy(c)print('id(c)-->', id(c))    # 0x03print('id(d)-->', id(d))    # 0x04
​
​a[1] = 100b[1] = 800print(f'c: {c}')    # [6, 7, [1, 100, 3], [11, 800, 33]]print(f'd: {d}')    # [6, 7, [1, 2, 3], [11, 22, 33]]
​
​
# 深拷贝不可变类型: 若为不可变类型直接就引用了, 不开辟新的内存空间
def dm05_深拷贝不可变类型():a = (1, 2, 3)b = (11, 22, 33)c = (a, b)
​d = copy.deepcopy(c)print(id(c))    # 0x03print(id(d))    # 0x03print("c/d内存空间相同, 说明c和d指向相同的内存空间")
​
​
​
​
# 在main函数中测试
if __name__ == '__main__':# dm01_普通赋值()# dm02_浅拷贝可变类型()# dm03_浅拷贝不可变类型()# dm04_深拷贝可变类型()dm05_深拷贝不可变类型()

图解深浅拷贝

普通赋值内存图

浅拷贝操作可变类型

浅拷贝操作不可变类型

深拷贝操作可变类型

深拷贝操作不可变类型

等同于普通赋值操作和浅拷贝操作不可变类型

总结

list1 = [1, 2, list2]

深浅拷贝操作不可变类型时相当于普通赋值操作, 即增加地址指向, 并不会重新开辟内存地址

浅拷贝操作可变类型: 拷贝第一层, 拷贝内容为:list0 = [1, 2, list2的地址指向]

修改list2的内容对拷贝后的数据直接影响, 修改list1无影响

深拷贝操作可变类型: 拷贝所有可变类型的层级, 即: 将list1拷贝, 并将list1中的list2同时拷贝一份, 修改元数据对拷贝后的数据无影响, 重新开辟内存空间

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • tomcat redis minio nginx windows开机自启
  • Python刷算法题必备技巧总结
  • Fluent 超音速射流噪声仿真分析
  • 697.数组的度
  • Marked: 一款高效、轻量级且全功能的Markdown解析器
  • 【C语言必学知识点六】自定义类型——结构体
  • 单品月GMV破4900W,2024防晒衣赛道在狂飙!
  • 以下是一些对公打款的测试方法
  • 【微信小程序】自定义 tabBar
  • 计算机毕设选题推荐-基于python的豆瓣电子图书数据可视化分析
  • Python脚本参数总结:argparse库基础用法
  • docker容器使用aconda运行python程序
  • KVM是什么,如何给一台Linux系统使用KVM技术变成好几个不同配置的Linux系统?
  • 回首“八年级上册语文课本”-----原文+感慨
  • angular xlsx-style,复杂表头样式导出
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • Angular 2 DI - IoC DI - 1
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • Git的一些常用操作
  • go语言学习初探(一)
  • If…else
  • Iterator 和 for...of 循环
  • Javascript基础之Array数组API
  • js如何打印object对象
  • PHP 7 修改了什么呢 -- 2
  • ReactNativeweexDeviceOne对比
  • v-if和v-for连用出现的问题
  • Vim Clutch | 面向脚踏板编程……
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 笨办法学C 练习34:动态数组
  • 复杂数据处理
  • 将 Measurements 和 Units 应用到物理学
  • 解析带emoji和链接的聊天系统消息
  • 两列自适应布局方案整理
  • 面试总结JavaScript篇
  • 前言-如何学习区块链
  • 云大使推广中的常见热门问题
  • MPAndroidChart 教程:Y轴 YAxis
  • #《AI中文版》V3 第 1 章 概述
  • #预处理和函数的对比以及条件编译
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (C++哈希表01)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第1节 (全局数据、栈和堆)
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (MATLAB)第五章-矩阵运算
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (过滤器)Filter和(监听器)listener
  • (剑指Offer)面试题34:丑数
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (四)Linux Shell编程——输入输出重定向
  • (转)shell中括号的特殊用法 linux if多条件判断
  • *** 2003
  • . ./ bash dash source 这五种执行shell脚本方式 区别