目录
1、总体要求
-
学员信息管理系统
------ 用于管理学员的相关信息,其中,学号为学员的唯一识别信息,不能重复,姓名和其他的信息可以重复。以下为基本功能要求:
(1)登录认证:要求先通过用户名和密码验证,通过之后才能进入系统进行相应的功能使用,如果可以有管理员和普通用户的区分会更好,不同的用户分配不同的操作权限。
(2)新增学员信息:可以连续增加多个学员信息,增加完成后提示是否继续、保存、退出等。
(3)删除学员信息:先显示学员列表给用户看,然后再删除对应学员,删除完成后提示是否继续、保存、退出等。
(4)修改学员信息:若添加信息时输入错误可进行修改,同样先把学员列表显示出来,再让用户选择相应信息进行修改,修改完成后提示是否继续、保存、退出等。
(5)查找学员信息:根据学员姓名,查询该学员的相关信息。
(6)显示全部学员:直接展示所有学员的全部信息,可以选择按添加时间顺序或者按学号的顺序来显示。
(7)学员统计分析:对所有学员的相关信息进行统计,显示男女性别分布和年龄分布等情况。
(8)文件操作:进行新增、删除和修改操作的时候,可以自动将学员的信息写入文件,进行永久存储,下次使用管理系统的时候,先读取文件里面的信息,然后进行新的操作。
2、需求分析
-
基本思路
(1)按照以上要求,可以成设计一个学员管理的类,相关的各个功能以类方法的形式来处理实现;
(2)学员管理系统,由若干个学员的信息组成,每个学员的信息包括:学号、姓名、性别、年龄、爱好,可以以字典来存放;
(3)先设置程序入口,并用学员管理类创建一个学员管理的对象,用此对象来调用类的各种方法:首先调用登录认证,验证通过之后再调用主要的逻辑实现方法,在主方法中去调用增、删、改、查等各个功能实现方法;
(4)类的主方法中显示功能菜单,供用户选择操作。每选择一个功能,都会进入新的页面,每次操作完成后返回主页,依旧显示功能菜单,直至用户退出系统。
3、框架设计
# 定义学员管理类
class Student_Manager(object):
# 初始化...(可以把各个功能实现需要用到的临时变量在此处创建并初始化)
def __init__(self):
pass
# 登录认证--不同用户实现不同的功能权限
def login_auth(self):
pass
# 显示功能选项
def login_welcome(self):
pass
# 主功能页面--前提是通过了登录认证
def main(self):
pass
# 新增学员信息--可以连续添加多个学员信息
def add_student_data(self)
pass
# 删除学员信息
def remove_student_data(self):
pass
# 修改学员信息
def mod_student_data(self):
pass
# 查找学员信息--根据姓名查找,重名的需要全部显示出来
def srh_student_data(self):
pass
# 显示全部学员--可选显示顺序
def display_student_data(self):
pass
# 数据统计--统计男女学员人数、年龄段分布等
def data_statistics(self):
pass
# 清空系统数据
def clear_student_data(self):
pass
# 保存数据--将临时变量self.student_list里面的学生信息遍历出来,保存到txt文件
def save_student_data(self):
pass
# 读取数据--读取过去存储数据的txt文件,将里面数据存到临时变量self.student_list中
def read_student_data(self):
pass
# 程序入口
if __name__ == "__main__":
# 创建对象
manager = Student_Manager()
# 先进行登录验证
manager.login_auth()
# 通过验证后再调用主方法
manager.main()
4、细节设计
4.1 程序入口
if __name__ == "__main__":
manager = Student_Manager()
var1 = manager.login_auth()
# 通过了认证即可执行main()方法
if var1 == "已取得全部权限" or var1 == "已取得只读权限":
manager.main(var1)
# 没通过认证,啥也别谈
else:
print(var1)
4.2 学员管理类
4.2.1 初始化
首先在创建类时,需要将后续要用的临时变量进行初始化。功能选项可以打包成字典,让功能函数与键之间建立映射关系。允许登录的用户的用户名、密码以及他们的不同权限,都可以在此处先声明好。
class Student_Manager(object):
def __init__(self):
self.student_list = [] # 用于存放学员信息,单个学员的信息以字典的形式存在
self.id_list = [] # 用于存放学员的学号,便于判断后续新增或者修改时候会不会重号
# 选项功能字典
self.option_func_dict = {
'1': self.add_student_data,
'2': self.remove_student_data,
'3': self.mod_student_data,
'4': self.srh_student_data,
'5': self.display_student_data,
'6': self.data_statistics,
'7': self.clear_student_data
}
# 已授权的用户列表
self.user_list = [
{'username': 'admin', 'password': '1234', 'permission': '全部权限'},
{'username': 'guest', 'password': '0000', 'permission': '只读权限'}
]
4.2.2 登录认证
# 登录认证--不同用户实现不同的功能权限
def login_auth(self):
print("=" * 12, "欢迎登录学员管理系统", "=" * 12)
for i in range(5): # 设置登录认证次数为5次
username = input("用户名:").strip()
password = input("密码:").strip()
for user in self.user_list:
if username == user['username'] and password == user['password']:
# 判断用户权限,执行相应权限的功能
if user['permission'] == '全部权限':
return "已取得全部权限"
elif user['permission'] == '只读权限':
return "已取得只读权限"
else:
if i < (5 - 1):
print(f"用户名或密码错误,剩余验证次数{4 - i}次,请重新输入。")
else:
print(f"用户名或密码错误,今日验证次数已用完,请明天再尝试登录。")
input("按任意键关闭程序...")
return "---大宝天天见!---"
让用户名和密码的验证只能循环固定次数,即相当于限制登录验证次数,这样可以提高系统的安全性,效果如下:
全部权限和只读权限的选项功能界面一样,但是只读权限的用户无法使用添加、删除和修改这样一些需要写入的权限的功能,效果如下:
4.2.3 功能菜单
# 显示功能选项
def login_welcome(self):
print("=" * 12, "欢迎进入学员管理系统", "=" * 12)
print('\t', "*" * 5, "1、添加学员信息", "*" * 5)
print('\t', "*" * 5, "2、删除学员信息", "*" * 5)
print('\t', "*" * 5, "3、修改学员信息", "*" * 5)
print('\t', "*" * 5, "4、查找学员信息", "*" * 5)
print('\t', "*" * 5, "5、显示全部学员", "*" * 5)
print('\t', "*" * 5, "6、学员统计信息", "*" * 5)
print('\t', "*" * 5, "7、清空系统数据", "*" * 5)
print('\t', "*" * 5, "0、退出管理系统", "*" * 5)
print("=" * 46)
# 主功能页面--前提是通过了登录认证
def main(self, temp):
while True:
self.login_welcome() # 显示欢迎界面,给出功能选项
self.student_list.clear() # 清空学员列表
self.id_list.clear() # 清空学员学号列表
self.read_student_data() # 读取已经存储到txt内的数据,重新赋值给student_list
option = input("请输入数字,选择对应的功能:").strip()
if option == "0":
print("~~~欢迎下次使用~~~")
input("按任意键关闭程序...")
break
elif option in self.option_func_dict:
if temp == "已取得全部权限":
self.option_func_dict[option]() # 根据键值直接调用对应功能函数
elif temp == "已取得只读权限":
if option == "1" or option == "2" or option == "3" or option == "7":
print("当前用户权限不足!你仅可以选择4、5、6对应功能,或者退出系统。")
input("按任意键返回主页...")
elif option == "4":
self.srh_student_data()
elif option == "5":
self.display_student_data()
elif option == "6":
self.data_statistics()
else:
print("~~~输入错误,请输入正确的数字!~~~")
input("按任意键返回主页...")
效果如下(后面效果皆展示使用具有全部权限的账号登录认证成功后的效果):
4.2.4 文件操作
- 读取文件
------ 每次返回主页功能选项界面后,需要重新读取文件内数据,因为有些操作会更新文件内数据。
# 读取数据--读取过去存储数据的txt文件,将里面数据存到临时变量self.student_list中
def read_student_data(self):
try:
with open("./student_data.txt", "r", encoding="utf-8") as f:
# 避开第一行的标题,从第二行开始遍历,将数据存储到临时变量self.student_list
for line in f.readlines()[1:]:
stu_id, stu_name, stu_sex, stu_age, stu_hobby = line.strip().split("\t")
student = {'学号': stu_id, '姓名': stu_name, '性别': stu_sex, '年龄': stu_age, '爱好': stu_hobby}
self.student_list.append(student)
self.id_list.append(stu_id)
except (FileNotFoundError, ValueError): # 避免初次启动时,因为txt文件还没创建或者为空而报错
print("当前学员系统暂无数据,请先添加学员信息!")
首次使用的时候,因为文件为空,所以用 try…except…来捕捉异常,避免读取文件时报错导致程序无法运行。
初次进入管理系统后,读取效果如下:
- 写入文件
------ 每次用户进行新增、删除、修改、清空等操作时,提示用户保存,如果保存,就将数据写入txt文件。
# 保存数据--将临时变量self.student_list里面的学生信息遍历出来,保存到txt文件
def save_student_data(self):
if self.student_list: # 判断学员列表是否为空,只有列表不为空才执行写入
with open("./student_data.txt", "w", encoding="utf-8") as f:
f.write("学号\t姓名\t性别\t年龄\t爱好\n") # 首行写入标题,便于用户查看文件
for student in self.student_list:
f.write(f"{student['学号']}\t{student['姓名']}\t{student['性别']}\t{student['年龄']}\t{student['爱好']}\n")
print("---保存成功---")
else:
print("---暂无数据需要保存---")
4.2.5 新增学员
# 新增学员信息--可以连续添加多个学员信息
def add_student_data(self):
print("=" * 12, "欢迎进入新增学员系统", "=" * 12)
while True:
stu_id = input("请输入学员学号:").strip()
if stu_id in self.id_list:
print(f"学号{stu_id}---已存在,请重新输入!")
continue
student = {'学号': stu_id,
'姓名': input("请输入学员姓名:").strip(),
'性别': input("请输入学员性别:").strip(),
'年龄': input("请输入学员年龄:").strip(),
'爱好': input("请输入学员爱好:").strip()
}
for value in student.values():
if not value:
print(f"信息不能为空---添加失败,请重新输入!")
break
else:
self.student_list.append(student)
self.id_list.append(stu_id)
print(f"{student['学号']}号学员:{student['姓名']}---添加成功!")
num = input("是否继续添加(1:继续,2:保存并退出,3:不保存并退出):").strip()
if num == '2':
self.save_student_data()
break
if num == '3':
break
选择新增功能后,进入新界面,效果如下:
因为学号是唯一的,所以在后面继续添加学员的时候,如果重号了,会提示用户重新输入。
最后添加完成选择保存后,我们可以看下txt文件已经被成功写入数据:
4.2.6 删除学员
# 删除学员信息
def remove_student_data(self):
print("=" * 12, "欢迎进入删减学员系统", "=" * 12)
if self.student_list: # 先判断数据是否为空,避免进入死循环
print("学员列表如下:") # 先打印下学员列表,避免输入不存在的学员信息,优化用户体验
for index, student in enumerate(self.student_list):
print(
f"索引值:{index}-- 学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
while True:
try:
index = int(input("请选择要删除的学员信息(输入对应索引值):").strip())
student = self.student_list[index]
self.student_list.remove(student)
self.id_list.remove(student['学号'])
print(f"{student['学号']}号学员:{student['姓名']}---删除成功!")
except (IndexError, ValueError): # 防止输入非整数类型或者超出索引而发生报错
print("索引值错误,请重新输入!")
continue
num = input("是否继续删除(1:继续,2:保存并退出,3:不保存并退出):").strip()
if num == '2':
self.save_student_data()
break
if num == '3':
break
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
选择保存后,效果如下:(如果不保存退出,则txt文件内的数据不会发生改变)
4.2.7 修改学员
# 修改学员信息
def mod_student_data(self):
print("=" * 12, "欢迎进入修改学员系统", "=" * 12)
if self.student_list: # 先判断数据是否为空,避免进入死循环
print("学员列表如下:") # 先打印下学员列表,避免输入不存在的学员信息,优化用户体验
for index, student in enumerate(self.student_list):
print(
f"索引值:{index}-- 学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
while True:
try:
index = int(input("请选择要修改的学员信息(输入对应索引值):").strip())
student = self.student_list[index]
self.mod_choice(student) # 直接传递所选学员字典
except (IndexError, ValueError): # 防止输入非整数类型或者超出索引而发生报错
print("索引值错误,请重新输入!")
continue
num = input("是否继续修改(1:继续,2:保存并退出,3:不保存并退出):").strip()
if num == '2':
self.save_student_data()
break
if num == '3':
break
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
为了优化用户体验,我们允许用户选择具体修改某一项信息或者全部信息,具体代码实现如下:
# 具体修改选项--优化用户体验,让用户可以选择需要修改的具体信息
def mod_choice(self, student):
print("该学员信息如下:")
print(f"学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
print("请选择要修改的信息:")
print("1:全部修改 2:仅学号 3:仅姓名 4:仅性别 5:仅年龄 6:仅爱好")
num = input("请输入数字选择要修改的信息:").strip()
if num == '1':
while True:
new_id = input("请输入修改后的学号:").strip()
if new_id not in self.id_list or new_id == student['学号']:
self.id_list.remove(student['学号'])
student['学号'] = new_id
student['姓名'] = input("请输入修改后的姓名:").strip()
student['性别'] = input("请输入修改后的性别:").strip()
student['年龄'] = input("请输入修改后的年龄:").strip()
student['爱好'] = input("请输入修改后的爱好:").strip()
self.id_list.append(student['学号'])
break
else:
print(f"学号{new_id}---已存在,请重新输入!")
elif num == '2':
while True:
new_id = input("请输入修改后的学号:").strip()
if new_id not in self.id_list:
self.id_list.remove(student['学号'])
student['学号'] = new_id
self.id_list.append(student['学号'])
break
else:
print(f"学号{new_id}---已存在,请重新输入!")
elif num == '3':
student['姓名'] = input("请输入修改后的姓名:").strip()
elif num == '4':
student['性别'] = input("请输入修改后的性别:").strip()
elif num == '5':
student['年龄'] = input("请输入修改后的年龄:").strip()
elif num == '6':
student['爱好'] = input("请输入修改后的爱好:").strip()
else:
print("~~~输入错误,请输入正确的数字!~~~")
return self.mod_choice(student)
print(f"{student['学号']}号学员:{student['姓名']}---修改成功!")
print("修改后信息为:")
print(f"学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
可以选择修改某一项信息,也可以选择修改全部信息,实现效果如下:
更多效果,大家可以自行尝试,如遇到bug,欢迎大家与我分享交流~
4.2.8 查找学员
# 查找学员信息--根据姓名查找,重名的需要全部显示出来
def srh_student_data(self):
print("=" * 12, "欢迎进入学员查询系统", "=" * 12)
if self.student_list: # 先判断数据是否为空,避免进入死循环
while True:
# 将所有学员的姓名暂时存储到一个列表中,用于判断
name_list = [student["姓名"] for student in self.student_list]
stu_name = input("请输入要查找的学员姓名:").strip()
if name_list.count(stu_name) == 0:
print(f"姓名为{stu_name}的学员---不存在!")
else:
for student in self.student_list:
if student["姓名"] == stu_name:
print(
f"学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
num = input("是否继续查找(1:继续,2:退出):").strip()
if num == '2':
break
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
不管要查找的学员是否存在,或者有同名的多个学员,都给出对应的提示和结果,效果如下:
4.2.9 显示全部学员
# 显示全部学员--可选显示顺序
def display_student_data(self):
print("=" * 12, "欢迎进入学员展示系统", "=" * 12)
if self.student_list: # 判断数据是否为空,避免报错
num = input("请选择显示方式(1:按学员添加时间顺序,2:按学号排序):").strip()
if num == '2':
self.student_list.sort(key=lambda x: x['学号'])
print("学员列表如下:")
for index, student in enumerate(self.student_list):
print(
f"索引值:{index}-- 学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
效果如下:
4.2.10 学员数据统计
# 数据统计--统计男女学员人数、年龄段分布等
def data_statistics(self):
print("=" * 12, "欢迎进入学员统计系统", "=" * 12)
if self.student_list: # 先判断数据是否为空,避免报错
print(f"当前学员总人数:{len(self.student_list)}人")
male_num = female_num = 0
yong_num = middle_num = large_num = old_num = older_num = grandpa_num = 0
age_list = []
for student in self.student_list:
if student["性别"] == "男":
male_num += 1
if student["性别"] == "女":
female_num += 1
if int(student["年龄"]) <= 20:
yong_num += 1
if 20 < int(student["年龄"]) <= 30:
middle_num += 1
if 30 < int(student["年龄"]) <= 40:
large_num += 1
if 40 < int(student["年龄"]) <= 50:
old_num += 1
if 50 < int(student["年龄"]) <= 60:
older_num += 1
if int(student["年龄"]) > 60:
grandpa_num += 1
age_list.append(int(student["年龄"]))
other_num = len(self.student_list) - male_num - female_num
print("男女性别分布如下:")
print(f"男性学员数量:{male_num}人,占比:{male_num / len(self.student_list):.1%}")
print(f"女性学员数量:{female_num}人,占比:{female_num / len(self.student_list):.1%}")
print(f"无性别学员数量:{other_num}人,占比:{other_num / len(self.student_list):.1%}\n")
print("各年龄段分布:")
print(f"20岁(含20)以下学员数量:{yong_num}人,占比:{yong_num / len(self.student_list):.1%}")
print(f"20-30岁(含30)学员数量:{middle_num}人,占比:{middle_num / len(self.student_list):.1%}")
print(f"30-40岁(含40)学员数量:{large_num}人, 占比:{large_num / len(self.student_list):.1%}")
print(f"40-50岁(含50)学员数量:{old_num}人, 占比:{old_num / len(self.student_list):.1%}")
print(f"50-60岁(含60)学员数量:{older_num}人, 占比:{older_num / len(self.student_list):.1%}")
print(f"60岁以上学员数量:{grandpa_num}人,占比:{grandpa_num / len(self.student_list):.1%}")
print(f"平均年龄水平:{sum(age_list)/len(age_list):.1f}岁")
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
学员数据统计效果如下:
4.2.11 清空系统数据
------ 为了优化体验,增加一个清空系统数据的功能。
# 清空系统数据
def clear_student_data(self):
print("=" * 12, "欢迎进入学员清空系统", "=" * 12)
if self.student_list: # 先判断数据是否为空
print("重要提示:数据清空后,无法恢复,请谨慎操作!!!")
num = input("请确认是否清空(1:确认,2:取消):").strip()
if num == "1":
self.student_list = [{'学号': "", '姓名': "", '性别': "", '年龄': "", '爱好': ""}] # 放入空值字典,防止save的时候判断为空而不执行保存
self.id_list.clear()
self.save_student_data()
print("---系统数据已全部清空---")
else:
print("---已取消清空---")
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
因为清空操作比较敏感,选择进入该功能页面后第一时间给出用户“重要提醒”,然后再让用户确认清空操作,如果取消,保存数据的文件就不会发生任何变动;如果确认清空,则将学员列表清空后,存入一个空值的字典数据到文件中,效果如下:
可以打开txt文件检查,里面的学员数据已经被清空,只保留了标题信息,效果如下:
5、总结
- 代码结构:代码结构比较清晰,注释充足且易于理解,但是还存在很大优化空间。
- 功能实现:代码实现的学员管理系统的主要功能比较完整,包括增删改查统计等,这些功能的实现基本上符合需求。
- 异常处理:代码实现中考虑到了各种异常情况,具备了一定的异常处理能力。比如,在删除和修改功能中,如果输入的索引值不存在,会给出提示而不是直接报错。还有初次启动程序时,文件不存在或者为空,也会给出提示而不是报错。
- 性能优化: 代码在性能方面没有太大问题,对于这种较小的系统来说效率是可以接受的。但如果要处理的数据量较大,可能需要更高效的数据结构,或者更优的设计思路。
- 用户体验:在功能实现上,代码可读性较高,变量命名规范。但是print语句较多,如果学员数量较大,打印内容会过多,影响用户体验。
- 其他:以上代码中数据存储是列表形式,如果学员数量较大,索引查询效率会变低,可以改为字典形式存储。(此条为小伙伴的建议,暂时还未完成测试是否有助提高效率)
完整代码如下:
------ 欢迎大家提出宝贵意见,我们相互交流学习,共同进步。
class Student_Manager(object):
# 初始化...
def __init__(self):
self.student_list = []
self.id_list = []
# 选项功能字典
self.option_func_dict = {
'1': self.add_student_data,
'2': self.remove_student_data,
'3': self.mod_student_data,
'4': self.srh_student_data,
'5': self.display_student_data,
'6': self.data_statistics,
'7': self.clear_student_data
}
# 已授权的用户列表
self.user_list = [
{'username': 'admin', 'password': '1234', 'permission': '全部权限'},
{'username': 'guest', 'password': '0000', 'permission': '只读权限'}
]
# 新增学员信息--可以连续添加多个学员信息
def add_student_data(self):
print("=" * 12, "欢迎进入新增学员系统", "=" * 12)
while True:
stu_id = input("请输入学员学号:").strip()
if stu_id in self.id_list:
print(f"学号{stu_id}---已存在,请重新输入!")
continue
student = {'学号': stu_id,
'姓名': input("请输入学员姓名:").strip(),
'性别': input("请输入学员性别:").strip(),
'年龄': input("请输入学员年龄:").strip(),
'爱好': input("请输入学员爱好:").strip()
}
for value in student.values():
if not value:
print(f"信息不能为空---添加失败,请重新输入!")
break
else:
self.student_list.append(student)
self.id_list.append(stu_id)
print(f"{student['学号']}号学员:{student['姓名']}---添加成功!")
num = input("是否继续添加(1:继续,2:保存并退出,3:不保存并退出):").strip()
if num == '2':
self.save_student_data()
break
if num == '3':
break
# 删除学员信息
def remove_student_data(self):
print("=" * 12, "欢迎进入删减学员系统", "=" * 12)
if self.student_list: # 先判断数据是否为空,避免进入死循环
print("学员列表如下:") # 先打印下学员列表,避免输入不存在的学员信息,优化用户体验
for index, student in enumerate(self.student_list):
print(
f"索引值:{index}-- 学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
while True:
try:
index = int(input("请选择要删除的学员信息(输入对应索引值):").strip())
student = self.student_list[index]
self.student_list.remove(student)
self.id_list.remove(student['学号'])
print(f"{student['学号']}号学员:{student['姓名']}---删除成功!")
except (IndexError, ValueError): # 防止输入非整数类型或者超出索引而发生报错
print("索引值错误,请重新输入!")
continue
num = input("是否继续删除(1:继续,2:保存并退出,3:不保存并退出):").strip()
if num == '2':
self.save_student_data()
break
if num == '3':
break
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
# 修改学员信息
def mod_student_data(self):
print("=" * 12, "欢迎进入修改学员系统", "=" * 12)
if self.student_list: # 先判断数据是否为空,避免进入死循环
print("学员列表如下:") # 先打印下学员列表,避免输入不存在的学员信息,优化用户体验
for index, student in enumerate(self.student_list):
print(
f"索引值:{index}-- 学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
while True:
try:
index = int(input("请选择要修改的学员信息(输入对应索引值):").strip())
student = self.student_list[index]
self.mod_choice(student) # 直接传递所选学员字典
except (IndexError, ValueError): # 防止输入非整数类型或者超出索引而发生报错
print("索引值错误,请重新输入!")
continue
num = input("是否继续修改(1:继续,2:保存并退出,3:不保存并退出):").strip()
if num == '2':
self.save_student_data()
break
if num == '3':
break
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
# 具体修改选项--优化用户体验,让用户可以选择需要修改的具体信息
def mod_choice(self, student):
print("该学员信息如下:")
print(f"学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
print("请选择要修改的信息:")
print("1:全部修改 2:仅学号 3:仅姓名 4:仅性别 5:仅年龄 6:仅爱好")
num = input("请输入数字选择要修改的信息:").strip()
if num == '1':
while True:
new_id = input("请输入修改后的学号:").strip()
if new_id not in self.id_list or new_id == student['学号']:
self.id_list.remove(student['学号'])
student['学号'] = new_id
student['姓名'] = input("请输入修改后的姓名:").strip()
student['性别'] = input("请输入修改后的性别:").strip()
student['年龄'] = input("请输入修改后的年龄:").strip()
student['爱好'] = input("请输入修改后的爱好:").strip()
self.id_list.append(student['学号'])
break
else:
print(f"学号{new_id}---已存在,请重新输入!")
elif num == '2':
while True:
new_id = input("请输入修改后的学号:").strip()
if new_id not in self.id_list:
self.id_list.remove(student['学号'])
student['学号'] = new_id
self.id_list.append(student['学号'])
break
else:
print(f"学号{new_id}---已存在,请重新输入!")
elif num == '3':
student['姓名'] = input("请输入修改后的姓名:").strip()
elif num == '4':
student['性别'] = input("请输入修改后的性别:").strip()
elif num == '5':
student['年龄'] = input("请输入修改后的年龄:").strip()
elif num == '6':
student['爱好'] = input("请输入修改后的爱好:").strip()
else:
print("~~~输入错误,请输入正确的数字!~~~")
return self.mod_choice(student)
print(f"{student['学号']}号学员:{student['姓名']}---修改成功!")
print("修改后信息为:")
print(f"学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
# 查找学员信息--根据姓名查找,重名的需要全部显示出来
def srh_student_data(self):
print("=" * 12, "欢迎进入学员查询系统", "=" * 12)
if self.student_list: # 先判断数据是否为空,避免进入死循环
while True:
# 将所有学员的姓名暂时存储到一个列表中,用于判断
name_list = [student["姓名"] for student in self.student_list]
stu_name = input("请输入要查找的学员姓名:").strip()
if name_list.count(stu_name) == 0:
print(f"姓名为{stu_name}的学员---不存在!")
else:
for student in self.student_list:
if student["姓名"] == stu_name:
print(
f"学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
num = input("是否继续查找(1:继续,2:退出):").strip()
if num == '2':
break
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
# 显示全部学员--可选显示顺序
def display_student_data(self):
print("=" * 12, "欢迎进入学员展示系统", "=" * 12)
if self.student_list: # 判断数据是否为空,避免报错
num = input("请选择显示方式(1:按学员添加时间顺序,2:按学号排序):").strip()
if num == '2':
self.student_list.sort(key=lambda x: x['学号'])
print("学员列表如下:")
for index, student in enumerate(self.student_list):
print(
f"索引值:{index}-- 学号:{student['学号']},姓名:{student['姓名']},性别:{student['性别']},年龄:{student['年龄']},爱好:{student['爱好']}")
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
# 数据统计--统计男女学员人数、年龄段分布等
def data_statistics(self):
print("=" * 12, "欢迎进入学员统计系统", "=" * 12)
if self.student_list: # 先判断数据是否为空,避免报错
print(f"当前学员总人数:{len(self.student_list)}人")
male_num = female_num = 0
yong_num = middle_num = large_num = old_num = older_num = grandpa_num = 0
age_list = []
for student in self.student_list:
if student["性别"] == "男":
male_num += 1
if student["性别"] == "女":
female_num += 1
if int(student["年龄"]) <= 20:
yong_num += 1
if 20 < int(student["年龄"]) <= 30:
middle_num += 1
if 30 < int(student["年龄"]) <= 40:
large_num += 1
if 40 < int(student["年龄"]) <= 50:
old_num += 1
if 50 < int(student["年龄"]) <= 60:
older_num += 1
if int(student["年龄"]) > 60:
grandpa_num += 1
age_list.append(int(student["年龄"]))
other_num = len(self.student_list) - male_num - female_num
print("男女性别分布如下:")
print(f"男性学员数量:{male_num}人,占比:{male_num / len(self.student_list):.1%}")
print(f"女性学员数量:{female_num}人,占比:{female_num / len(self.student_list):.1%}")
print(f"无性别学员数量:{other_num}人,占比:{other_num / len(self.student_list):.1%}\n")
print("各年龄段分布:")
print(f"20岁(含20)以下学员数量:{yong_num}人,占比:{yong_num / len(self.student_list):.1%}")
print(f"20-30岁(含30)学员数量:{middle_num}人,占比:{middle_num / len(self.student_list):.1%}")
print(f"30-40岁(含40)学员数量:{large_num}人, 占比:{large_num / len(self.student_list):.1%}")
print(f"40-50岁(含50)学员数量:{old_num}人, 占比:{old_num / len(self.student_list):.1%}")
print(f"50-60岁(含60)学员数量:{older_num}人, 占比:{older_num / len(self.student_list):.1%}")
print(f"60岁以上学员数量:{grandpa_num}人,占比:{grandpa_num / len(self.student_list):.1%}")
print(f"平均年龄水平:{sum(age_list)/len(age_list):.1f}岁")
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
# 清空系统数据
def clear_student_data(self):
print("=" * 12, "欢迎进入学员清空系统", "=" * 12)
if self.student_list: # 先判断数据是否为空
print("重要提示:数据清空后,无法恢复,请谨慎操作!!!")
num = input("请确认是否清空(1:确认,2:取消):").strip()
if num == "1":
self.student_list = [{'学号': "", '姓名': "", '性别': "", '年龄': "", '爱好': ""}] # 放入空值字典,防止save的时候判断为空而不执行保存
self.id_list.clear()
self.save_student_data()
print("---系统数据已全部清空---")
else:
print("---已取消清空---")
else:
print("当前学员系统暂无数据!")
input("按任意键返回主页...")
# 保存数据--将临时变量self.student_list里面的学生信息遍历出来,保存到txt文件
def save_student_data(self):
if self.student_list: # 判断学员列表是否为空,只有列表不为空才执行写入
with open("./student_data.txt", "w", encoding="utf-8") as f:
f.write("学号\t姓名\t性别\t年龄\t爱好\n") # 首行写入标题,便于用户查看文件
for student in self.student_list:
f.write(f"{student['学号']}\t{student['姓名']}\t{student['性别']}\t{student['年龄']}\t{student['爱好']}\n")
print("---保存成功---")
else:
print("---暂无数据需要保存---")
# 读取数据--读取过去存储数据的txt文件,将里面数据存到临时变量self.student_list中
def read_student_data(self):
try:
with open("./student_data.txt", "r", encoding="utf-8") as f:
# 避开第一行的标题,从第二行开始遍历,将数据存储到临时变量self.student_list
for line in f.readlines()[1:]:
stu_id, stu_name, stu_sex, stu_age, stu_hobby = line.strip().split("\t")
student = {'学号': stu_id, '姓名': stu_name, '性别': stu_sex, '年龄': stu_age, '爱好': stu_hobby}
self.student_list.append(student)
self.id_list.append(stu_id)
except (FileNotFoundError, ValueError): # 避免初次启动时,因为txt文件还没创建或为空而报错
print("当前学员系统暂无数据,请先添加学员信息!")
# 登录认证--不同用户实现不同的功能权限
def login_auth(self):
print("=" * 12, "欢迎登录学员管理系统", "=" * 12)
for i in range(5): # 设置登录认证次数为5次
username = input("用户名:").strip()
password = input("密码:").strip()
for user in self.user_list:
if username == user['username'] and password == user['password']:
# 判断用户权限,执行相应权限的功能
if user['permission'] == '全部权限':
return "已取得全部权限"
elif user['permission'] == '只读权限':
return "已取得只读权限"
else:
if i < (5 - 1):
print(f"用户名或密码错误,剩余验证次数{4 - i}次,请重新输入。")
else:
print(f"用户名或密码错误,今日验证次数已用完,请明天再尝试登录。")
input("按任意键关闭程序...")
return "---大宝天天见!---"
# 显示功能选项
def login_welcome(self):
print("=" * 12, "欢迎进入学员管理系统", "=" * 12)
print('\t', "*" * 5, "1、添加学员信息", "*" * 5)
print('\t', "*" * 5, "2、删除学员信息", "*" * 5)
print('\t', "*" * 5, "3、修改学员信息", "*" * 5)
print('\t', "*" * 5, "4、查找学员信息", "*" * 5)
print('\t', "*" * 5, "5、显示全部学员", "*" * 5)
print('\t', "*" * 5, "6、学员统计信息", "*" * 5)
print('\t', "*" * 5, "7、清空系统数据", "*" * 5)
print('\t', "*" * 5, "0、退出管理系统", "*" * 5)
print("=" * 46)
# 主功能页面--前提是通过了登录认证
def main(self, temp):
while True:
self.login_welcome() # 打印欢迎界面
self.student_list.clear() # 清空学员列表
self.id_list.clear() # 清空学员学号列表
self.read_student_data() # 读取已经存储到txt内的数据,重新赋值给student_list
option = input("请输入数字,选择对应的功能:").strip()
if option == "0":
print("~~~欢迎下次使用~~~")
input("按任意键关闭程序...")
break
elif option in self.option_func_dict:
if temp == "已取得全部权限":
self.option_func_dict[option]() # 根据键值直接调用对应功能函数
elif temp == "已取得只读权限":
if option == "1" or option == "2" or option == "3" or option == "7":
print("当前用户权限不足!你仅可以选择4、5、6对应功能,或者退出系统。")
input("按任意键返回主页...")
elif option == "4":
self.srh_student_data()
elif option == "5":
self.display_student_data()
elif option == "6":
self.data_statistics()
else:
print("~~~输入错误,请输入正确的数字!~~~")
input("按任意键返回主页...")
# 程序入口
if __name__ == "__main__":
manager = Student_Manager()
var1 = manager.login_auth()
# 通过了认证即可执行main()方法
if var1 == "已取得全部权限" or var1 == "已取得只读权限":
manager.main(var1)
# 没通过认证,啥也别谈
else:
print(var1)