第十五课:综合实战升级——成绩小管家 Pro
入门 python教学 · 2026-10-21 · 阅读 3

还记得第十一课的小管家吗?它已经能存数据(十二课)、能画图(十四课)了。这一课是 Python 线的总装:把所有本事合到一个程序里,再补上查询、删除、统计报告三个新功能,做成一个真正能用的"成绩小管家 Pro"。学完这一课,你就有了一个可以投到作品区的完整作品。
一、Pro 版多了什么
| 菜单 | 功能 | 新旧 |
|---|---|---|
| 1 | 录入成绩(存完自动保存到文件) | 十一 + 十二课 |
| 2 | 查看全部 | 十一课 |
| 3 | 按姓名查成绩 | ★新 |
| 4 | 删除学生 | ★新 |
| 5 | 统计报告(平均分/最高分/及格率) | ★新(十一课的升级) |
| 6 | 生成成绩图(存成图片) | 十四课 |
| 0 | 退出 | — |
二、新功能逐个看
查成绩:在列表里一个一个比对姓名,找到了就打印、收工(return);全比对完还没有,就是没这个人。这个"从头找到尾"的办法有个正经名字——顺序查找,先记住它,学考那边还会碰面。
def find_student():
name = input("要查谁的成绩:")
for s in students:
if s["姓名"] == name:
print(f"{name} 的成绩是 {s['成绩']} 分")
return # 找到了,收工
print("没找到这个学生") # 循环走完都没 return,说明没有
删除学生:和查找是同一个套路,只是找到后多一步 remove 把他从列表拿掉,并且立刻 save_data() 同步到文件——不然下次启动,他又"复活"了(第十二课挑战题的坑,就是这个)。
def delete_student():
name = input("要删除谁:")
for s in students:
if s["姓名"] == name:
students.remove(s)
save_data() # 别忘了同步文件!
print(f"已删除 {name}")
return
print("没找到这个学生")
统计报告:把平均分、最高分、及格率一次算清。及格率就是"及格人数 ÷ 总人数",循环数一遍就行:
def show_report():
if not students:
print("还没有数据,先录入吧")
return
scores = [s["成绩"] for s in students]
avg = sum(scores) / len(scores)
best = max(students, key=lambda s: s["成绩"])
passed = 0
for sc in scores:
if sc >= 60:
passed += 1
rate = passed / len(scores) * 100
print(f"共 {len(scores)} 人 | 平均分 {avg:.1f} | "
f"最高分 {best['姓名']} {best['成绩']} 分 | 及格率 {rate:.0f}%")
其中第一行 scores = [s["成绩"] for s in students] 是个新写法,叫列表推导式:一行把所有人的成绩挑出来组成新列表。等价于写个 for 循环 append,只是更简洁,以后会常遇到。
生成成绩图:把第十四课的画图代码打包成函数,注意最后加一句 plt.close() 把图关掉——不然连续生成多次,图会叠在一起:
def make_chart():
if not students:
print("还没有数据,先录入吧")
return
names = [s["姓名"] for s in students]
scores = [s["成绩"] for s in students]
avg = sum(scores) / len(scores)
plt.bar(names, scores)
plt.axhline(avg, color="red", linestyle="--") # 平均线
plt.axhline(60, color="green", linestyle=":") # 及格线
plt.title(f"全班成绩(平均分 {avg:.1f})")
plt.xlabel("姓名")
plt.ylabel("成绩")
plt.ylim(0, 100)
plt.savefig("score_chart.png")
plt.close()
print("成绩图已保存为 score_chart.png")
三、完整代码(可直接抄走运行)
import os
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
students = []
FILENAME = "scores.txt"
def save_data():
with open(FILENAME, "w", encoding="utf-8") as f:
for s in students:
f.write(f"{s['姓名']},{s['成绩']}\n")
def load_data():
if not os.path.exists(FILENAME):
return
with open(FILENAME, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
name, score = line.split(",")
students.append({"姓名": name, "成绩": float(score)})
def add_student():
name = input("姓名:")
score = float(input("成绩:"))
students.append({"姓名": name, "成绩": score})
save_data()
print("录入成功!")
def show_all():
if not students:
print("还没有数据,先录入吧")
return
for s in students:
print(f"{s['姓名']}:{s['成绩']}分")
def find_student():
name = input("要查谁的成绩:")
for s in students:
if s["姓名"] == name:
print(f"{name} 的成绩是 {s['成绩']} 分")
return
print("没找到这个学生")
def delete_student():
name = input("要删除谁:")
for s in students:
if s["姓名"] == name:
students.remove(s)
save_data()
print(f"已删除 {name}")
return
print("没找到这个学生")
def show_report():
if not students:
print("还没有数据,先录入吧")
return
scores = [s["成绩"] for s in students]
avg = sum(scores) / len(scores)
best = max(students, key=lambda s: s["成绩"])
passed = 0
for sc in scores:
if sc >= 60:
passed += 1
rate = passed / len(scores) * 100
print(f"共 {len(scores)} 人 | 平均分 {avg:.1f} | "
f"最高分 {best['姓名']} {best['成绩']} 分 | 及格率 {rate:.0f}%")
def make_chart():
if not students:
print("还没有数据,先录入吧")
return
names = [s["姓名"] for s in students]
scores = [s["成绩"] for s in students]
avg = sum(scores) / len(scores)
plt.bar(names, scores)
plt.axhline(avg, color="red", linestyle="--")
plt.axhline(60, color="green", linestyle=":")
plt.title(f"全班成绩(平均分 {avg:.1f})")
plt.xlabel("姓名")
plt.ylabel("成绩")
plt.ylim(0, 100)
plt.savefig("score_chart.png")
plt.close()
print("成绩图已保存为 score_chart.png")
load_data()
while True:
print("1.录入 2.查看全部 3.查成绩 4.删学生 5.统计报告 6.生成成绩图 0.退出")
choice = input("请选择:")
if choice == "1":
add_student()
elif choice == "2":
show_all()
elif choice == "3":
find_student()
elif choice == "4":
delete_student()
elif choice == "5":
show_report()
elif choice == "6":
make_chart()
elif choice == "0":
print("再见!数据都存在 scores.txt 里了。")
break
else:
print("没有这个选项,重新选吧")
四、回头看:你已经会了多少
| 这个程序的部位 | 来自哪一课 |
|---|---|
| 菜单 + while 循环 + if 分支 | 第六、七课 |
| 字典装进列表的数据结构 | 第八、九课 |
| 每个功能一个函数 | 第十课 |
| save / load 文件存取 | 第十二课 |
| split 拆行、字符串拼接 | 第十三课 |
| 画图存图 | 第十四课 |
不知不觉,你已经能独立写出一个上百行、功能完整的小软件了。这就是编程学习的正常节奏:每课一小块,最后拼成一个大件。把你的小管家 Pro 打磨一下(换个主题也行:通讯录、图书管理、零花钱账本,骨架都一样),投到本站的作品区去吧。
练一练
1. 排行榜:给菜单加"7.排行榜":把学生按成绩从高到低打印出来(提示:sorted(students, key=lambda s: s["成绩"], reverse=True))。
2. 改成绩:加"8.改成绩":先按姓名找到人,再改他的成绩,别忘保存。想一想它跟哪两个功能是同套路?
3. 挑战题:如果每人要存三科成绩(语数英),数据结构该怎么改?文件一行该怎么写?先在纸上设计,别急着写代码——真实开发就是先设计、后动手。
下一课是 Python 线的彩蛋:用 turtle 海龟绘图,纯玩,放松一下。
学·教在线
小ta