Python实战案例:基于文件操作的学生成绩管理系统

Python实战案例:基于文件操作的学生成绩管理系统



案例背景

在我们学习了Python的文件操作基础(如文件读写、with open语句、异常处理等)之后,我们需要一个实战项目来巩固所学知识。
本文将通过一个基于文件操作的学生成绩管理系统,加深理解文件操作核心逻辑,以及对之前学习的条件判断、循环、函数等基础语法进行复习


一、案例源码

file_path = "students.txt"  # 文件路径
students = {}
# 学生字典,结构示例:{"张三": {"语文":80.0, "数学":90.0, "英语":85.0, "总分":255.0}, ...}
# 由于字典键的唯一性,如有同名学生,可添加序号加以区分
subjects = ["语文", "数学", "英语", "物理", "化学"]  # 学科名称列表(如需增删学科需在这里修改)
# 可以尝试在代码功能模块添加一条,动态增删学科数据


def show_menu():
    print("\n" + "*" * 50)
    print("欢迎使用【学生成绩管理系统】")
    print("1. 添加学生成绩信息")
    print("2. 显示全体学生成绩信息")
    print("3. 删除学生成绩信息")
    print("4. 修改学生成绩信息")
    print("5. 成绩总分排名[默认高 → 低]")
    print("6. 单科成绩排名[默认高 → 低]")
    print("0. 退出系统")
    print("*" * 50)


def load_from_file():
    # global students
    students.clear()  # 重置数据

    try:
        with open(file_path, "r", encoding="utf-8") as f:
            lines = f.readlines()
    except FileNotFoundError:
        return  # 文件不存在时静默返回

    # current_student = {}  # 当前学生临时字典
    # name = None  # 当前学生姓名

    for line in lines:
        line = line.strip()
        if not line:
            continue  # 跳过空行

        # 处理当前学生
        if line.startswith("姓名:"):  # 处理当前学生键
            name = line.split(":", 1)[1].strip()
            students[name] = {}  # 添加当前学生字典的键(值为空字典)
        elif ":" in line:  # 处理当前学生值(各科成绩键值对)
            parts = line.split(":", 1)
            subject, score = parts[0].strip(), parts[1].strip()
            if subject in subjects:  # 只处理学科成绩
                try:
                    students[name][subject] = float(score)
                except ValueError:
                    print(f"忽略无效成绩: {line}")
            elif subject == "总分":  # 计算总分
                # 重新计算总分并更新,以免直接读取文件数据时可能出现的错误
                students[name][subject] = sum(
                    students[name].get(subj, 0) for subj in subjects
                )


def save_to_file():
    try:
        with open(file_path, "w", encoding="utf-8") as f:
            for name, scores in students.items():
                f.write(f"姓名:{name}\n")
                # 写入各科成绩
                for subject in subjects:
                    score = scores.get(subject, 0)
                    f.write(f"{subject}:{score}\n")
                # 写入总分
                f.write(f"总分:{scores['总分']}\n\n")
        print("数据已成功保存到文件")
    except PermissionError:
        print("错误:没有文件写入权限!")
    except Exception as e:
        print(f"保存文件时出错: {e}")


def check_score(score):
    # 成绩并不一定是整数,也可能是浮点数,比如90.5
    # 处理成绩数据
    try:
        score = round(float(score), 1)  # 转换为浮点数保留一位小数
        if 0 <= score <= 100:
            return score
        else:
            print("成绩数值必须在0-100之间!")
            return None
    except ValueError:
        print("请输入有效的学科成绩!")
        return None


def add_student():
    print("\n" + "=" * 50)
    print("当前功能模块: 添加学生成绩信息")
    print("=" * 50)

    name = input("请输入学生姓名:")

    if name in students:
        print(f"\n 学生 {name} 已存在!")
        return  # 退出函数

    students[name] = {}
    scores = {subject: 0 for subject in subjects}

    for subject in scores.keys():
        while subject:  # 此处条件恒为真,即无限循环,直到用户输入有效成绩
            score = input(f"请输入 [ {subject} ] 学科成绩(0-100):")
            score = check_score(score)  # 调用函数检测用户输入合法性
            print(score)
            if score is None:
                # 如果用户输入内容不符合要求,则重新输入
                continue

            # 存储数据
            scores[subject] = score
            students[name][subject] = score
            break  # 数据合法且存储后,退出当前学科while循环

    else:  # for循环正常结束后,计算总分并保存至文件
        students[name]["总分"] = sum(scores.values())
        save_to_file()
        print(f"\n 添加学生 [ {name} ] 学科成绩信息成功!")


def show_students():
    print("\n" + "=" * 50)
    print("当前功能模块: 显示全体学生成绩信息")
    print("=" * 50)

    if not students:
        print("\n 未查询到有效的学生信息!")
        return  # 退出函数

    # 以制表符作为分隔符,打印学生信息
    print()
    print(f"{"姓名":^10}", end="\t")  # 打印表头
    for subject in subjects:
        print(subject, end="\t")
    else:
        print()  # 循环结束换行
    print("-" * len(subjects) * 10)

    # 打印学生成绩表内容
    for name, scores in students.items():
        print(f"{name:^10}", end="\t")  # 打印表头
        for subject in subjects:
            score = scores.get(subject, 0)
            print(score, end="\t")
        else:
            print()  # 循环结束换行


def del_student():
    print("\n" + "=" * 50)
    print("当前功能模块: 删除学生成绩信息")
    print("=" * 50)

    name = input("请输入要删除的学生姓名:")

    if name in students:
        # 显示将被删除的学生信息
        print(f"\n即将删除成绩数据的学生信息: ")
        print(f"姓名: {name}")
        for subject in subjects:
            score = students[name].get(subject, 0)
            print(f"{subject}: {score}")
        choice = input("确认删除吗?(Y 确认/其他任意键取消操作): ").strip().lower()
        if choice == "y":
            del students[name]
            save_to_file()
            print(f"\n已成功删除学生 [ {name} ] 相关信息!")
        else:
            print("\n操作已取消")
    else:
        print(f"\n 未查询到学生 [ {name} ] 的相关信息!")


def modify_student():
    print("\n" + "=" * 50)
    print("当前功能模块: 修改学生成绩信息")
    print("=" * 50)

    name = input("请输入要修改的学生姓名:")

    if name not in students:
        print(f"\n 学生 {name} 不存在!")
        return  # 退出函数

    print(f"\n当前需要修改的学生 [ {name} ] 的成绩信息:")
    for subject in subjects:
        print(f"{subject}: {students[name].get(subject, 0)}")

    scores = {subject: 0 for subject in subjects}

    for subject in scores.keys():
        while subject:
            score = (
                input(f"\n请输入新的{subject}成绩(直接回车保持当前值): ")
                .strip()
                .lower()
            )
            if score == "":
                if subject in students[name]:
                    # 保持当前成绩,跳出本学科while循环
                    scores[subject] = students[name][subject]  # 使用原始值
                    print(f"\n{subject}成绩未做任何修改")
                    break
                else:
                    # 未查询到该学科成绩,设置默认值0
                    scores[subject] = 0
                    print(f"\n 未查询到学生 [ {name} ] 的 {subject} 成绩信息!")
                    print(f"已默认设置 {subject} 成绩为0")
                    break

            score = check_score(score)  # 调用函数检测用户输入合法性

            if score is None:
                # 如果用户输入内容不符合要求,则重新输入
                continue

            # 修改数据
            scores[subject] = score
            students[name][subject] = score
            break

    else:  # for循环正常结束后,计算总分并保存至文件
        students[name]["总分"] = sum(scores.values())
        save_to_file()
        print(f"\n学生 [ {name} ] 的成绩信息已更新!")


def sort_total_score(reverse=True):
    print("\n" + "=" * 50)
    print("当前功能模块: 成绩总分排名[默认高 → 低]")
    print("=" * 50)

    if not students:
        print("\n 未查询到有效的学生信息!")
        return  # 退出函数

    # 创建用于存储姓名和总分的列表
    total_scoret_list = []
    for name, scores in students.items():
        total_scoret_list.append(
            {
                "姓名": name,
                "总分": scores.get("总分", 0),
            }
        )

    # 按总分排序
    total_scoret_list.sort(key=lambda x: x["总分"], reverse=reverse)

    order = "从高到低" if reverse else "从低到高"
    print()
    print(f"学生成绩 [ 总分 ] 按{order}排序结果为")
    print()
    print(f"排名\t{"姓名":>10}\t\t总分")
    print("-" * 40)

    for rank, student in enumerate(total_scoret_list, 1):
        print(f"{rank}\t{student["姓名"]:>10}\t\t{student["总分"]}")


# 生成学生单科成绩排名函数
def sort_subject_score(reverse=True):
    print("\n" + "=" * 50)
    print("当前功能模块: 单科成绩排名[默认高 → 低]")
    print("=" * 50)
    print()

    if not students:
        print("\n 未查询到有效的学生信息!")
        return  # 退出函数

    subject = input("请输入要查询的科目:").strip().lower()

    if subject not in subjects:
        print(f"\n 未查询到科目 [ {subject} ] 的相关信息!")
        return  # 退出函数

    # 创建用于存储姓名和学科分数的列表
    subject_score_list = []

    for name, scores in students.items():
        subject_score_list.append(
            {
                "姓名": name,
                subject: scores.get(subject, 0),
            }
        )

    # 按学科分数排序
    subject_score_list.sort(key=lambda x: x[subject], reverse=reverse)

    order = "从高到低" if reverse else "从低到高"
    print()
    print(f"学生 [ {subject} ] 成绩按{order}排序结果为")
    print()
    print(f"排名\t{"姓名":>10}\t\t{subject}成绩")
    print("-" * 40)

    for rank, student in enumerate(subject_score_list, 1):
        print(f"{rank}\t{student["姓名"]:>10}\t\t{student[subject]}")


def test_data():
    """生成测试数据的函数"""
    import random

    names = [
        "张三", "李四", "王五", "赵六", "田七", "周八", "吴九", 
        "郑十", "冯十一", "陈十二", "褚十三", "卫十四", "蒋十五", "沈十六",
        "韩十七", "杨十八", "朱十九", "秦二十", "尤二十一", "吕二十二", "施二十三",
        "张二十四", "孔二十五", "曹二十六", "严二十七", "华二十八", "金二十九", "魏三十",
        "陶三十一", "姜三十二"
        ]

    students = {
        name: {  # 模拟真实成绩数据(分数包含小数)
            subject: random.randint(60, 99) + random.choice([0.5, 1.0])
            for subject in subjects
        }
        for name in names
    }
    for name in students:
        students[name]["总分"] = sum(students[name].values())  # 添加总分键值对
    return students


if __name__ == "__main__":
    # # 使用测试数据
    # students = test_data()
    # # 保存数据
    # save_to_file()  
    # # 取消以上几行代码注释,可使用测试数据,验证程序功能
    
    # 程序启动时加载数据
    load_from_file()
    
    # 主程序循环
    while True:
        show_menu()
        option = input("\n请输入您的选项:")
        if option == "1":
            add_student()
        elif option == "2":
            show_students()
        elif option == "3":
            del_student()
        elif option == "4":
            modify_student()
        elif option == "5":
            sort_total_score()  # 填入参数False可以从低到高排序
        elif option == "6":
            sort_subject_score()  # 填入参数False可以从低到高排序
        elif option == "0":
            print("\n" + "=" * 40)
            print("感谢使用学生成绩管理系统,再见!")
            print("=" * 40)
            break
        else:
            print("\n您的输入有误,请重新输入!")

二、案例说明

以上案例代码实现了一个学生成绩管理系统,能够对学生的成绩进行添加、查询、修改、删除等操作,包括数据持久化(通过文件操作读写数据),也可以按照总分或单科成绩进行排名

  1. 数据结构与全局变量

    students = {}
    subjects = ["语文", "数学", "英语", "物理", "化学"]
    

    students:这是一个嵌套字典,用于存储学生信息。外层字典的键是学生姓名,值是另一个字典,包含各科成绩和总分
    subjects:包含所有学科名称的列表,修改这个列表就能增减系统管理的学科

  2. 文件操作函数

    def load_from_file():
        # 从文件读取学生数据到内存
    def save_to_file():
        # 将内存中的学生数据保存到文件
    

    数据文件采用文本格式,每个学生的记录包括姓名、各科成绩和总分,不同学生记录之间用空行分隔
    程序启动时会自动调用 load_from_file() 加载数据,每次数据修改后会调用 save_to_file() 保存数据

  3. 数据验证函数

    def check_score(score):
    	# 用于验证用户输入的分数数据是否合法
    

    该函数会确保成绩在0-100的范围内,并且对成绩进行格式化处理

  4. 核心功能函数

    def add_student():
        # 添加新学生及其成绩
    def show_students():
        # 显示所有学生的成绩信息
    def del_student():
        # 删除指定学生的成绩信息
    def modify_student():
        # 修改指定学生的成绩信息
    def sort_total_score(reverse=True):
        # 按总分排名,默认从高到低
    def sort_subject_score(reverse=True):
        # 按单科成绩排名,默认从高到低
    

    这些函数实现了系统的主要功能逻辑,包括数据的增删改查和排序

  5. 用户交互设计
    采用菜单驱动的交互方式,主菜单提供7个操作选项
    每个功能模块都有清晰的提示信息,操作完成后会给出相应的反馈
    数据展示使用表格形式,结构清晰,便于查看

  6. 测试与异常处理
    test_data() 函数可生成模拟数据,方便测试系统功能
    文件操作中加入了异常处理,能应对文件不存在、权限不足等常见问题


三、案例总结

本案例通过Python文件操作和基础语法实现了一个轻量级学生成绩管理系统 ,覆盖学生成绩的增、删、改、查、排序全流程操作,支持总分和单科成绩排名,满足基础成绩管理需求 。通过文本文件存储数据(students.txt),程序启动时自动加载数据,操作后实时保存,确保数据不丢失 。采用菜单驱动界面和表格化数据展示,使用户操作逻辑清晰,反馈明确。将功能拆解为独立函数(如文件读写、数据验证、功能模块),降低耦合度,便于维护和扩展。代码中的部分print()函数采用for循环遍历动态打印输出方式,即使是增删学科,导致数据结构改变,也能完整输出内容。这种设计,本质是将可变因素(学科列表)与不变逻辑(增删改查流程)分离,符合软件开发中的开闭原则(对扩展开放,对修改关闭),这一点,也是我们在学习过程中应该注意并掌握的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值