Python: 综合项目:学生成绩管理(下)
前两课完成了数据层和逻辑层。这一课把一切串起来——写一个完整的命令行菜单界面。完成这课后,你就拥有了一个真正可用的学生成绩管理系统。
1. 完整系统代码
将前三课的代码合并到一个文件中,加上菜单界面:
▶ 示例:完整成绩管理系统
TEXT
📖 仅展示
import json
import os
import statistics
# ====== 配置 ======
DATA_FILE = "grade_system.json"
DEFAULT_DATA = {
"students": {},
"subjects": ["语文", "数学", "英语"],
"classes": []
}
# ====== 数据层 ======
def load_data():
if not os.path.exists(DATA_FILE):
save_data(DEFAULT_DATA.copy())
return DEFAULT_DATA.copy()
with open(DATA_FILE, "r", encoding="utf-8") as f:
return json.load(f)
def save_data(data):
with open(DATA_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def add_student(student_id, name, class_name):
data = load_data()
if student_id in data["students"]:
return False, f"学号 {student_id} 已存在!"
data["students"][student_id] = {"name": name, "class_name": class_name, "scores": {}}
if class_name not in data["classes"]:
data["classes"].append(class_name)
save_data(data)
return True, f"已添加学生:{name}({student_id})"
def delete_student(student_id):
data = load_data()
if student_id not in data["students"]:
return False, f"学号 {student_id} 不存在!"
name = data["students"][student_id]["name"]
del data["students"][student_id]
save_data(data)
return True, f"已删除学生:{name}"
def add_score(student_id, subject, score):
data = load_data()
if student_id not in data["students"]:
return False, f"学号 {student_id} 不存在!"
if subject not in data["subjects"]:
return False, f"科目 {subject} 不存在!"
if not isinstance(score, (int, float)) or score < 0 or score > 100:
return False, "成绩必须在 0~100 之间!"
data["students"][student_id]["scores"][subject] = score
save_data(data)
return True, f"已录入 {data['students'][student_id]['name']} 的 {subject}:{score}分"
# ====== 逻辑层 ======
def get_student_report(student_id):
data = load_data()
student = data["students"].get(student_id)
if not student:
return None
report = {"name": student["name"], "class_name": student["class_name"],
"scores": dict(student["scores"])}
scores = list(student["scores"].values())
if scores:
report["average"] = round(sum(scores) / len(scores), 1)
report["total"] = sum(scores)
report["max_score"] = max(scores)
report["min_score"] = min(scores)
else:
report["average"] = report["total"] = report["max_score"] = report["min_score"] = None
return report
def get_class_ranking(class_name=None):
data = load_data()
results = []
for sid, info in data["students"].items():
if class_name and info["class_name"] != class_name:
continue
scores = list(info["scores"].values())
total = sum(scores) if scores else 0
avg = round(total / len(scores), 1) if scores else 0
results.append({"id": sid, "name": info["name"], "class": info["class_name"],
"total": total, "avg": avg, "count": len(scores)})
results.sort(key=lambda x: x["total"], reverse=True)
for i, r in enumerate(results, 1):
r["rank"] = i
return results
def get_subject_stats():
data = load_data()
stats = {}
for subject in data["subjects"]:
scores = []
for info in data["students"].values():
if subject in info["scores"]:
scores.append(info["scores"][subject])
if scores:
stats[subject] = {"avg": round(sum(scores) / len(scores), 1),
"max": max(scores), "min": min(scores), "count": len(scores)}
return stats
# ====== 展示层 ======
def show_main_menu():
print("\n" + "=" * 40)
print("🎓 学生成绩管理系统")
print("=" * 40)
print("1. 学生管理")
print("2. 成绩管理")
print("3. 统计查询")
print("4. 查看数据")
print("5. 退出")
print("=" * 40)
def show_student_menu():
print("\n--- 学生管理 ---")
print("1. 添加学生")
print("2. 删除学生")
print("3. 返回主菜单")
def show_score_menu():
print("\n--- 成绩管理 ---")
print("1. 录入成绩")
print("2. 返回主菜单")
def show_stats_menu():
print("\n--- 统计查询 ---")
print("1. 个人成绩单")
print("2. 全校排名")
print("3. 各科平均分")
print("4. 返回主菜单")
def student_management():
"""学生管理子菜单"""
while True:
show_student_menu()
choice = input("请选择:").strip()
if choice == "1":
sid = input("学号:").strip()
name = input("姓名:").strip()
cls = input("班级:").strip()
success, msg = add_student(sid, name, cls)
print(f" {'✅' if success else '❌'} {msg}")
elif choice == "2":
sid = input("请输入要删除的学号:").strip()
success, msg = delete_student(sid)
print(f" {'✅' if success else '❌'} {msg}")
elif choice == "3":
break
else:
print("无效选择!")
def score_management():
"""成绩管理子菜单"""
while True:
show_score_menu()
choice = input("请选择:").strip()
if choice == "1":
sid = input("学号:").strip()
subject = input("科目:").strip()
try:
score = float(input("成绩(0-100):").strip())
except ValueError:
print("❌ 成绩必须是数字!")
continue
success, msg = add_score(sid, subject, score)
print(f" {'✅' if success else '❌'} {msg}")
elif choice == "2":
break
else:
print("无效选择!")
def stats_query():
"""统计查询子菜单"""
while True:
show_stats_menu()
choice = input("请选择:").strip()
if choice == "1":
sid = input("请输入学号:").strip()
report = get_student_report(sid)
if not report:
print("❌ 未找到该学生!")
continue
print(f"\n📋 {report['name']}({report['class_name']})成绩单")
print("-" * 25)
for subject, score in report["scores"].items():
print(f" {subject}:{score}")
if report["total"] is not None:
print(f" 总分:{report['total']}")
print(f" 平均分:{report['average']}")
print(f" 最高分:{report['max_score']}")
print(f" 最低分:{report['min_score']}")
else:
print(" (暂无成绩)")
elif choice == "2":
ranking = get_class_ranking()
if not ranking:
print("暂无数据!")
continue
print("\n🏆 全校排名")
print(f"{'排名':<4}{'姓名':<8}{'班级':<8}{'总分':<6}{'平均分':<6}")
print("-" * 32)
for r in ranking:
print(f"{r['rank']:<4}{r['name']:<8}{r['class']:<8}{r['total']:<6}{r['avg']:<6}")
elif choice == "3":
stats = get_subject_stats()
if not stats:
print("暂无成绩数据!")
continue
print("\n📊 各科成绩统计")
print(f"{'科目':<8}{'平均分':<8}{'最高':<6}{'最低':<6}{'人数':<4}")
print("-" * 32)
for subject, info in stats.items():
print(f"{subject:<8}{info['avg']:<8}{info['max']:<6}{info['min']:<6}{info['count']:<4}")
elif choice == "4":
break
else:
print("无效选择!")
def view_data():
"""查看原始数据"""
data = load_data()
students = data["students"]
if not students:
print("📭 暂无学生数据")
return
print(f"\n📚 共有 {len(students)} 名学生")
for sid, info in sorted(students.items()):
scores = info["scores"]
score_str = ", ".join(f"{s}:{v}" for s, v in scores.items()) if scores else "暂无成绩"
print(f" {sid} {info['name']}({info['class_name']})→ {score_str}")
# ====== 主程序 ======
def main():
print("🎓 欢迎使用学生成绩管理系统!")
while True:
show_main_menu()
choice = input("请选择操作 (1-5):").strip()
if choice == "1":
student_management()
elif choice == "2":
score_management()
elif choice == "3":
stats_query()
elif choice == "4":
view_data()
elif choice == "5":
print("感谢使用,再见!👋")
break
else:
print("无效选择,请输入 1-5。")
if __name__ == "__main__":
main()
2. 运行示例
TEXT
📖 仅展示
🎓 欢迎使用学生成绩管理系统!
========================================
🎓 学生成绩管理系统
========================================
1. 学生管理
2. 成绩管理
3. 统计查询
4. 查看数据
5. 退出
========================================
请选择操作 (1-5):1
--- 学生管理 ---
1. 添加学生
2. 删除学生
3. 返回主菜单
请选择:1
学号:2024001
姓名:Alice
班级:一班
✅ 已添加学生:Alice(2024001)
▶ 示例:JSON 数据读写(难度⭐)
PYTHON
import json
data = {
"students": {
"001": {"name": "Alice", "scores": {"数学": 90, "英语": 85}},
"002": {"name": "Bob", "scores": {"数学": 78, "英语": 92}}
},
"subjects": ["数学", "英语"]
}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print("=== 序列化 ===")
print(json_str)
loaded = json.loads(json_str)
print("\n=== 反序列化 ===")
for sid, info in loaded["students"].items():
avg = sum(info["scores"].values()) / len(info["scores"])
print(f"{info['name']}(学号{sid})平均分:{avg:.1f}")
输出:
TEXT
📖 仅展示
=== 序列化 ===
{
"students": {
"001": {
"name": "Alice",
"scores": {
"数学": 90,
"英语": 85
}
},
"002": {
"name": "Bob",
"scores": {
"数学": 78,
"英语": 92
}
}
},
"subjects": [
"数学",
"英语"
]
}
=== 反序列化 ===
Alice(学号001)平均分:87.5
Bob(学号002)平均分:85.0
▶ 示例:命令行菜单系统(难度⭐⭐)
PYTHON
def show_menu():
print("\n===== 简易菜单 =====")
print("1. 查看列表")
print("2. 添加项目")
print("3. 退出")
items = ["苹果", "香蕉"]
choices = ["1", "2", "3"]
for choice in choices:
show_menu()
print(f"用户选择:{choice}")
if choice == "1":
if not items:
print("列表为空")
else:
for i, item in enumerate(items, 1):
print(f" {i}. {item}")
elif choice == "2":
new_item = "橙子"
items.append(new_item)
print(f"已添加:{new_item}")
elif choice == "3":
print("再见!")
break
输出:
TEXT
📖 仅展示
===== 简易菜单 =====
1. 查看列表
2. 添加项目
3. 退出
用户选择:1
1. 苹果
2. 香蕉
===== 简易菜单 =====
1. 查看列表
2. 添加项目
3. 退出
用户选择:2
已添加:橙子
===== 简易菜单 =====
1. 查看列表
2. 添加项目
3. 退出
用户选择:3
再见!
3. 项目总结
| 层 | 类/模块 | 职责 |
|---|---|---|
| 数据层 | load/save_data |
JSON 文件读写 |
| 实体层 | add/delete_student |
学生 CRUD |
| 实体层 | add_score |
成绩 CRUD |
| 逻辑层 | get_student_report |
个人成绩单 |
| 逻辑层 | get_class_ranking |
排名计算 |
| 逻辑层 | get_subject_stats |
科目统计 |
| 展示层 | main/main_menu |
菜单循环 |
| 展示层 | student/score/stats_management |
子菜单 |
❓ 常见问题
Q 命令行菜单的
while True 不会死循环吗?A 不会,因为菜单里有一个选项(比如输入 0 或 q)会执行
break 跳出循环。只要确保每个菜单都有"退出"选项就行。Q 模糊搜索用
in 就够了,还需要正则表达式吗?A 对于这个项目
keyword in name 足够了。如果需要更复杂的搜索(比如只匹配开头、忽略大小写、多关键词组合),就需要正则表达式了,第31课会详细讲。Q 项目完成后怎么打包给别人用?
A 最简单的方式是直接发
.py 文件,对方装了 Python 就能运行。如果想做成可执行文件(.exe),可以用 PyInstaller:pip install pyinstaller && pyinstaller --onefile main.py。📖 小节
- 三层架构:数据层 → 逻辑层 → 展示层,各层职责清晰
- 数据层:JSON 文件的读写封装,增删改查基础操作
- 逻辑层:成绩统计、排名、分析等业务规则
- 展示层:菜单界面、输入输出、用户交互
- 异常处理:输入验证、空数据处理、文件不存在处理
- 项目总计约 200 行核心代码,实现了完整的学生成绩管理功能
📝 作业
-
基础题(难度⭐):运行完整系统,添加 3 个学生和他们的成绩,生成排名报表。
-
进阶题(难度⭐⭐):给系统增加一个"导出报表"功能——把排名结果导出为
ranking.csv文件(用csv模块)。 -
挑战题(难度⭐⭐⭐):不参考上面的代码,从零开始写一个"图书销售管理系统"。功能包括:添加图书(书名、作者、单价、库存)、销售登记(图书名称、数量 → 自动减少库存)、查看库存报表(按销量排序)。用 JSON 做数据持久化。