Bootstrap

【Python实现】学员管理系统(详细解析)

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)

;