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您的输入有误,请重新输入!")
二、案例说明
以上案例代码实现了一个学生成绩管理系统,能够对学生的成绩进行添加、查询、修改、删除等操作,包括数据持久化(通过文件操作读写数据),也可以按照总分或单科成绩进行排名
-
数据结构与全局变量
students = {} subjects = ["语文", "数学", "英语", "物理", "化学"]
students
:这是一个嵌套字典,用于存储学生信息。外层字典的键是学生姓名,值是另一个字典,包含各科成绩和总分
subjects
:包含所有学科名称的列表,修改这个列表就能增减系统管理的学科 -
文件操作函数
def load_from_file(): # 从文件读取学生数据到内存 def save_to_file(): # 将内存中的学生数据保存到文件
数据文件采用文本格式,每个学生的记录包括姓名、各科成绩和总分,不同学生记录之间用空行分隔
程序启动时会自动调用load_from_file()
加载数据,每次数据修改后会调用save_to_file()
保存数据 -
数据验证函数
def check_score(score): # 用于验证用户输入的分数数据是否合法
该函数会确保成绩在0-100的范围内,并且对成绩进行格式化处理
-
核心功能函数
def add_student(): # 添加新学生及其成绩 def show_students(): # 显示所有学生的成绩信息 def del_student(): # 删除指定学生的成绩信息 def modify_student(): # 修改指定学生的成绩信息 def sort_total_score(reverse=True): # 按总分排名,默认从高到低 def sort_subject_score(reverse=True): # 按单科成绩排名,默认从高到低
这些函数实现了系统的主要功能逻辑,包括数据的增删改查和排序
-
用户交互设计
采用菜单驱动的交互方式,主菜单提供7个操作选项
每个功能模块都有清晰的提示信息,操作完成后会给出相应的反馈
数据展示使用表格形式,结构清晰,便于查看 -
测试与异常处理
test_data()
函数可生成模拟数据,方便测试系统功能
文件操作中加入了异常处理,能应对文件不存在、权限不足等常见问题
三、案例总结
本案例通过Python文件操作和基础语法实现了一个轻量级学生成绩管理系统 ,覆盖学生成绩的增、删、改、查、排序全流程操作,支持总分和单科成绩排名,满足基础成绩管理需求 。通过文本文件存储数据(students.txt
),程序启动时自动加载数据,操作后实时保存,确保数据不丢失 。采用菜单驱动界面和表格化数据展示,使用户操作逻辑清晰,反馈明确。将功能拆解为独立函数(如文件读写、数据验证、功能模块),降低耦合度,便于维护和扩展。代码中的部分print()函数采用for循环遍历动态打印输出方式,即使是增删学科,导致数据结构改变,也能完整输出内容。这种设计,本质是将可变因素(学科列表)与不变逻辑(增删改查流程)分离,符合软件开发中的开闭原则(对扩展开放,对修改关闭),这一点,也是我们在学习过程中应该注意并掌握的。