1.11 Python 实战项目:命令行学生成绩管理系统
·
前言:综合运用所学知识
在前十篇文章中,我们系统学习了Python的基本语法、数据类型、控制结构、函数、文件操作等核心概念。现在,我们将通过一个完整的实战项目——命令行学生成绩管理系统,来综合运用所学的所有知识。
这个项目将涵盖以下Python核心概念:
- 变量与数据类型
- 条件语句与循环
- 函数定义与参数传递
- 文件读写操作
- 异常处理
- 数据结构(列表、字典)
- 模块化编程
通过这个项目,你不仅能够巩固所学知识,还能学会如何将零散的知识点组织成一个完整的应用程序。
一、 项目需求分析
1.1 系统功能需求
我们需要开发一个命令行界面的学生成绩管理系统,具备以下功能:
-
学生信息管理
- 添加学生信息(学号、姓名、成绩)
- 显示所有学生信息
- 查询学生信息
- 修改学生信息
- 删除学生信息
-
成绩统计分析
- 计算平均成绩
- 统计成绩分布
- 按成绩排序
-
数据持久化
- 将数据保存到文件
- 从文件加载数据
-
用户界面
- 提供友好的命令行菜单
- 输入验证和错误处理
1.2 数据结构设计
我们将使用字典来表示单个学生信息,使用列表来存储所有学生信息:
# 单个学生数据结构
student = {
"id": "2023001", # 学号
"name": "张三", # 姓名
"score": 85.5 # 成绩
}
# 所有学生数据
students = [student1, student2, student3, ...]
二、 项目架构设计
2.1 模块化设计
我们将系统分为多个模块,每个模块负责特定的功能:
- main.py - 主程序入口,控制程序流程
- student.py - 学生数据模型和操作
- file_io.py - 文件读写操作
- menu.py - 用户界面和菜单显示
2.2 函数设计
我们将创建以下核心函数:
add_student()- 添加学生信息show_all_students()- 显示所有学生信息search_student()- 查询学生信息update_student()- 修改学生信息delete_student()- 删除学生信息calculate_average()- 计算平均成绩show_score_distribution()- 显示成绩分布sort_students()- 按成绩排序save_to_file()- 保存数据到文件load_from_file()- 从文件加载数据
三、 代码实现
3.1 主程序模块 (main.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
命令行学生成绩管理系统 - 主程序模块
"""
import os
import sys
from student import *
from file_io import *
from menu import *
def main():
"""主函数"""
students = [] # 学生列表
# 程序启动时加载数据
students = load_from_file("students.dat")
if students:
print(f"成功加载 {len(students)} 条学生记录")
else:
print("未找到保存的数据,将使用空数据库")
while True:
show_main_menu()
choice = get_user_choice()
if choice == "1":
students = add_student(students)
elif choice == "2":
show_all_students(students)
elif choice == "3":
search_student(students)
elif choice == "4":
students = update_student(students)
elif choice == "5":
students = delete_student(students)
elif choice == "6":
calculate_average(students)
elif choice == "7":
show_score_distribution(students)
elif choice == "8":
students = sort_students(students)
elif choice == "9":
if save_to_file(students, "students.dat"):
print("数据保存成功")
elif choice == "10":
students = load_from_file("students.dat")
if students:
print(f"成功加载 {len(students)} 条学生记录")
elif choice == "0":
if confirm_exit():
# 退出前保存数据
save_to_file(students, "students.dat")
print("感谢使用学生成绩管理系统,再见!")
break
else:
print("无效选择,请重新输入")
input("\n按回车键继续...") # 暂停,让用户看到结果
if __name__ == "__main__":
main()
3.2 学生数据模块 (student.py)
"""
命令行学生成绩管理系统 - 学生数据模块
"""
def create_student(student_id, name, score):
"""
创建学生字典
参数:
student_id (str): 学号
name (str): 姓名
score (float): 成绩
返回:
dict: 学生字典
"""
return {
"id": student_id,
"name": name,
"score": float(score)
}
def add_student(students):
"""
添加学生信息
参数:
students (list): 学生列表
返回:
list: 更新后的学生列表
"""
print("\n=== 添加学生信息 ===")
# 获取学号并检查是否已存在
while True:
student_id = input("请输入学号: ").strip()
if not student_id:
print("学号不能为空,请重新输入")
continue
# 检查学号是否已存在
if any(s["id"] == student_id for s in students):
print("该学号已存在,请重新输入")
continue
break
# 获取姓名
while True:
name = input("请输入姓名: ").strip()
if not name:
print("姓名不能为空,请重新输入")
continue
break
# 获取成绩
while True:
try:
score = float(input("请输入成绩: "))
if score < 0 or score > 100:
print("成绩必须在0-100之间,请重新输入")
continue
break
except ValueError:
print("请输入有效的数字")
# 创建学生并添加到列表
new_student = create_student(student_id, name, score)
students.append(new_student)
print(f"成功添加学生: {name} (学号: {student_id}, 成绩: {score})")
return students
def show_all_students(students):
"""
显示所有学生信息
参数:
students (list): 学生列表
"""
print("\n=== 所有学生信息 ===")
if not students:
print("暂无学生数据")
return
# 打印表头
print(f"{'学号':<12} {'姓名':<10} {'成绩':<6} {'等级':<6}")
print("-" * 40)
# 打印每个学生信息
for student in students:
grade = get_grade(student["score"])
print(f"{student['id']:<12} {student['name']:<10} {student['score']:<6.1f} {grade:<6}")
def search_student(students):
"""
查询学生信息
参数:
students (list): 学生列表
"""
print("\n=== 查询学生信息 ===")
if not students:
print("暂无学生数据")
return
search_type = input("按学号查询(1) 按姓名查询(2): ").strip()
if search_type == "1":
student_id = input("请输入学号: ").strip()
found_students = [s for s in students if s["id"] == student_id]
elif search_type == "2":
name = input("请输入姓名: ").strip()
found_students = [s for s in students if s["name"] == name]
else:
print("无效选择")
return
if not found_students:
print("未找到匹配的学生")
return
# 显示找到的学生
print("\n查询结果:")
print(f"{'学号':<12} {'姓名':<10} {'成绩':<6} {'等级':<6}")
print("-" * 40)
for student in found_students:
grade = get_grade(student["score"])
print(f"{student['id']:<12} {student['name']:<10} {student['score']:<6.1f} {grade:<6}")
def update_student(students):
"""
修改学生信息
参数:
students (list): 学生列表
返回:
list: 更新后的学生列表
"""
print("\n=== 修改学生信息 ===")
if not students:
print("暂无学生数据")
return students
student_id = input("请输入要修改的学生学号: ").strip()
# 查找学生
for i, student in enumerate(students):
if student["id"] == student_id:
print(f"找到学生: {student['name']} (当前成绩: {student['score']})")
# 获取新成绩
while True:
try:
new_score = float(input("请输入新成绩: "))
if new_score < 0 or new_score > 100:
print("成绩必须在0-100之间,请重新输入")
continue
break
except ValueError:
print("请输入有效的数字")
# 更新成绩
students[i]["score"] = new_score
print(f"成功更新学生 {student['name']} 的成绩为: {new_score}")
return students
print("未找到该学号的学生")
return students
def delete_student(students):
"""
删除学生信息
参数:
students (list): 学生列表
返回:
list: 更新后的学生列表
"""
print("\n=== 删除学生信息 ===")
if not students:
print("暂无学生数据")
return students
student_id = input("请输入要删除的学生学号: ").strip()
# 查找学生
for i, student in enumerate(students):
if student["id"] == student_id:
print(f"找到学生: {student['name']} (成绩: {student['score']})")
# 确认删除
confirm = input("确认删除吗?(y/n): ").strip().lower()
if confirm == "y":
deleted_student = students.pop(i)
print(f"已删除学生: {deleted_student['name']}")
else:
print("取消删除")
return students
print("未找到该学号的学生")
return students
def calculate_average(students):
"""
计算平均成绩
参数:
students (list): 学生列表
"""
print("\n=== 计算平均成绩 ===")
if not students:
print("暂无学生数据")
return
total_score = sum(student["score"] for student in students)
average = total_score / len(students)
print(f"学生总数: {len(students)}")
print(f"平均成绩: {average:.2f}")
# 显示最高分和最低分
max_score = max(student["score"] for student in students)
min_score = min(student["score"] for student in students)
print(f"最高分: {max_score:.1f}")
print(f"最低分: {min_score:.1f}")
def show_score_distribution(students):
"""
显示成绩分布
参数:
students (list): 学生列表
"""
print("\n=== 成绩分布 ===")
if not students:
print("暂无学生数据")
return
# 初始化计数器
distribution = {
"优秀(90-100)": 0,
"良好(80-89)": 0,
"中等(70-79)": 0,
"及格(60-69)": 0,
"不及格(0-59)": 0
}
# 统计各分数段人数
for student in students:
score = student["score"]
if score >= 90:
distribution["优秀(90-100)"] += 1
elif score >= 80:
distribution["良好(80-89)"] += 1
elif score >= 70:
distribution["中等(70-79)"] += 1
elif score >= 60:
distribution["及格(60-69)"] += 1
else:
distribution["不及格(0-59)"] += 1
# 显示分布
total = len(students)
print("分数段分布:")
for category, count in distribution.items():
percentage = (count / total) * 100 if total > 0 else 0
print(f"{category}: {count}人 ({percentage:.1f}%)")
def sort_students(students):
"""
按成绩排序
参数:
students (list): 学生列表
返回:
list: 排序后的学生列表
"""
print("\n=== 按成绩排序 ===")
if not students:
print("暂无学生数据")
return students
# 选择排序方式
order = input("升序排序(1) 降序排序(2): ").strip()
if order == "1":
sorted_students = sorted(students, key=lambda x: x["score"])
print("已按成绩升序排序")
elif order == "2":
sorted_students = sorted(students, key=lambda x: x["score"], reverse=True)
print("已按成绩降序排序")
else:
print("无效选择,返回原顺序")
return students
# 显示排序后的结果
print(f"{'学号':<12} {'姓名':<10} {'成绩':<6} {'等级':<6}")
print("-" * 40)
for student in sorted_students:
grade = get_grade(student["score"])
print(f"{student['id']:<12} {student['name']:<10} {student['score']:<6.1f} {grade:<6}")
return sorted_students
def get_grade(score):
"""
根据成绩返回等级
参数:
score (float): 成绩
返回:
str: 等级
"""
if score >= 90:
return "优秀"
elif score >= 80:
return "良好"
elif score >= 70:
return "中等"
elif score >= 60:
return "及格"
else:
return "不及格"
3.3 文件操作模块 (file_io.py)
"""
命令行学生成绩管理系统 - 文件操作模块
"""
import pickle
import os
def save_to_file(students, filename):
"""
将学生数据保存到文件
参数:
students (list): 学生列表
filename (str): 文件名
返回:
bool: 成功返回True,失败返回False
"""
try:
with open(filename, "wb") as f:
pickle.dump(students, f)
return True
except Exception as e:
print(f"保存文件时出错: {e}")
return False
def load_from_file(filename):
"""
从文件加载学生数据
参数:
filename (str): 文件名
返回:
list: 学生列表,如果失败返回空列表
"""
if not os.path.exists(filename):
return []
try:
with open(filename, "rb") as f:
students = pickle.load(f)
return students
except Exception as e:
print(f"加载文件时出错: {e}")
return []
3.4 用户界面模块 (menu.py)
"""
命令行学生成绩管理系统 - 用户界面模块
"""
def show_main_menu():
"""
显示主菜单
"""
print("\n" + "=" * 50)
print("命令行学生成绩管理系统")
print("=" * 50)
print("1. 添加学生信息")
print("2. 显示所有学生")
print("3. 查询学生信息")
print("4. 修改学生成绩")
print("5. 删除学生信息")
print("6. 计算平均成绩")
print("7. 显示成绩分布")
print("8. 按成绩排序")
print("9. 保存数据到文件")
print("10. 从文件加载数据")
print("0. 退出系统")
print("=" * 50)
def get_user_choice():
"""
获取用户选择
返回:
str: 用户选择
"""
return input("请选择操作(0-10): ").strip()
def confirm_exit():
"""
确认退出
返回:
bool: 确认退出返回True,否则返回False
"""
confirm = input("确认退出吗?(y/n): ").strip().lower()
return confirm == "y"
四、 项目运行与测试
4.1 运行项目
将上述四个文件保存在同一目录下,然后运行主程序:
python main.py
4.2 功能测试
测试用例1:添加学生信息
请选择操作(0-10): 1
=== 添加学生信息 ===
请输入学号: 2023001
请输入姓名: 张三
请输入成绩: 85
成功添加学生: 张三 (学号: 2023001, 成绩: 85.0)
测试用例2:显示所有学生
请选择操作(0-10): 2
=== 所有学生信息 ===
学号 姓名 成绩 等级
----------------------------------------
2023001 张三 85.0 良好
测试用例3:计算平均成绩
请选择操作(0-10): 6
=== 计算平均成绩 ===
学生总数: 1
平均成绩: 85.00
最高分: 85.0
最低分: 85.0
测试用例4:保存数据到文件
请选择操作(0-10): 9
数据保存成功
测试用例5:退出系统
请选择操作(0-10): 0
确认退出吗?(y/n): y
感谢使用学生成绩管理系统,再见!
4.3 异常处理测试
系统应该能够正确处理各种异常情况:
- 输入非法成绩:输入非数字或超出0-100范围的成绩
- 重复学号:尝试添加已存在的学号
- 空数据操作:在没有数据时尝试显示、查询、计算等操作
- 文件操作错误:在没有文件时尝试加载数据
五、 项目扩展与优化
5.1 功能扩展建议
- 多科目支持:扩展为支持多个科目的成绩管理
- 班级管理:添加班级概念,支持按班级管理学生
- 高级统计:添加更复杂的统计分析功能(如标准差、方差等)
- 数据可视化:使用matplotlib等库添加数据可视化功能
- 用户认证:添加登录系统,区分管理员和普通用户权限
5.2 代码优化建议
- 使用类重构:将学生和管理功能封装为类
- 数据库支持:使用SQLite或其它数据库替代文件存储
- 配置文件:添加配置文件管理程序设置
- 日志系统:添加日志记录功能
- 单元测试:为各功能添加单元测试
5.3 用户体验优化
- 更友好的界面:使用curses库创建更友好的命令行界面
- 批量操作:支持批量导入/导出学生数据
- 搜索增强:支持更复杂的搜索条件(如按成绩范围搜索)
- 数据验证:增强输入数据的验证和错误提示
六、 项目总结
通过这个命令行学生成绩管理系统的开发,我们综合运用了Python的多个核心概念:
- 数据结构:使用列表和字典组织学生数据
- 流程控制:使用条件语句和循环实现程序逻辑
- 函数编程:使用函数模块化代码,提高可重用性
- 文件操作:使用pickle模块实现数据持久化
- 异常处理:处理各种可能的错误情况
- 用户交互:实现友好的命令行界面
这个项目不仅巩固了前面所学的知识,还展示了如何将这些知识组织成一个完整的应用程序。通过这个项目,你应该能够:
- 设计和实现一个完整的命令行应用程序
- 使用适当的数据结构组织数据
- 实现常见的数据操作功能(增删改查)
- 处理用户输入和异常情况
- 实现数据持久化功能
在实际开发中,你可以在此基础上继续扩展功能,或者将学到的模式应用到其它类型的应用程序中。
更多推荐

所有评论(0)