先说一下背景。这份“python第四次作业”是我这段时间带的一个入门班里的真实练习,题目是“学生成绩分析系统”。前面的三次作业分别是变量与类型、条件与循环、列表与字符串处理,到第四次就该把函数、字典、文件读写和基础统计串起来用了。说白了,这是从“能写代码”到“能写小工具”的一个转折点,很多同学也是从这一次作业开始真正体会到Python的实用性。这篇就完整记录一下这次作业的题目拆解、代码实现、调试过程和一些容易被忽略的坑,给同样卡在作业上的朋友一个参考。
1. 作业需求拆解与整体框架设计
1.1 作业题目的核心逻辑
这次的作业题目要求实现一个“学生成绩分析系统”,功能比较典型,基本覆盖了Python入门的核心知识点。原题大致要求如下:
- 支持录入学生信息,包括姓名、学号和课程成绩。
- 支持删除学生记录。
- 支持修改某个学生的成绩。
- 能计算班级的平均分、最高分、最低分和及格率。
- 将数据保存到文件,程序重启后能重新加载。
- 可选加分项:用matplotlib绘制成绩分布直方图。
我拿到题目后首先做的事不是写代码,而是把需求列成一张表,明确每个功能点背后对应的是什么知识点:
| 功能 | 涉及知识点 |
|---|---|
| 录入学生 | 字典、列表、输入输出 |
| 删除学生 | 列表遍历、字典删除 |
| 修改成绩 | 字典更新、条件判断 |
| 统计平均分/最高分/最低分 | 循环、列表操作、max/min函数 |
| 及格率计算 | 条件统计、百分比计算 |
| 文件保存与加载 | CSV文件读写、异常处理 |
| 可视化直方图 | matplotlib基础、数据处理 |
列出这张表之后,整个作业的脉络就清晰了。这不仅能帮自己理清思路,在写代码的时候也更容易判断哪些地方应该用什么方式实现。
1.2 编程环境的准备与工具选择
作业要求里没有限制编辑器,但我建议直接装一个纯正的Python环境,然后用VS Code写代码。装的时候注意勾选“Add Python to PATH”,这个如果不勾,后面在命令行里运行python命令会提示找不到,很多新手在这儿卡了半天。
版本选择上,装Python 3.10或3.11稳定版就行,不需要追最新。为什么?因为很多第三方库在最新版本上可能还没来得及适配,反而老版本更稳。我这边的经验是直接用Anaconda也行,自带了很多常用的库,省得后面可视化的时候还要单独装matplotlib。不过如果不想装这么大个全家桶,直接用官方Python解释器加pip安装也是可以的,命令就是:
bash复制pip install matplotlib
安装的时候如果遇到网络慢的情况,可以换成国内镜像源:
bash复制pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple
这个镜像源是清华的,速度快很多,我平常都习惯用这个。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心知识点拆解与方案选型
2.1 数据结构:字典与列表如何取舍
整个程序里最核心的数据结构就是怎么存学生信息。我先说说我当时在群里看到的几种写法。
第一种写法是用并列关系的外部结构,把学生信息放在一个列表里,每个学生是一个字典。这是最常见也最推荐的方式:
python复制students = [
{"name": "张三", "sno": "2024001", "score": 88},
{"name": "李四", "sno": "2024002", "score": 74}
]
这种结构的优点是清晰直观,遍历的时候能直接拿到每个学生的完整信息。缺点是如果学生数量大,遍历匹配会比较慢,不过对作业级别来说完全够用。
第二种写法是用学号做键的字典:
python复制students = {
"2024001": {"name": "张三", "score": 88},
"2024002": {"name": "李四", "score": 74}
}
这种结构的好处是查找某个学生时直接按学号取值就行,时间复杂度是O(1),不用遍历整个列表。坏处是如果同一个班级有多个学生想按姓名查找,就必须自己遍历value。
两种写法都能完成作业要求,我的建议是选择第一种。原因很简单:这个作业的核心操作是“遍历统计”,比如算平均分、最高分、最低分,这些操作需要遍历所有学生的成绩。用列表套字典的写法,计算时只需要一次for循环,逻辑最直接,也好调试。而且作业里需要展示的通常是一整张表,列表结构在打印输出的时候顺序是稳定的,体验更好。
2.2 函数设计:怎么拆才合理
第四次作业重点考察的就是函数的封装。很多同学会把所有逻辑全写在一个大while循环里,也能跑通,但代码会非常长,而且出了问题很难定位。我建议按照功能职责来拆函数,每个函数只干一件完整的事。
比如我最终拆出来的函数有这些:
load_data():从CSV文件加载学生数据。save_data():把学生数据保存到CSV文件。add_student():录入一个新学生。delete_student():按学号删除学生。modify_score():按学号修改成绩。show_all():展示所有学生信息。cal_statistics():计算并显示统计结果。draw_histogram():绘制成绩分布直方图。main():主菜单循环。
这里有一个新手常犯的问题,就是喜欢把所有输入输出都放主函数里,子函数只是被调用的“工具人”。这样做的结果是主函数非常臃肿,而子函数做不了独立的决策。更合理的做法是让每个子函数负责自己的输入和输出,主函数只做菜单跳转和流程控制。比如add_student(),它就是负责提示用户输入姓名、学号、成绩,然后添加到列表中,它内部可以把数据校验也做了。这样主函数看起来干净,每个功能模块也可以单独测试。
2.3 文件读写:存什么格式、怎么处理
文件保存这一块,我选了CSV格式,不用自造的.txt格式。原因是CSV可以直接用Excel打开,调试的时候看着方便,而且Python标准库的csv模块处理这个格式非常顺。如果你用自定义的分隔符(比如逗号或竖线)自己拼字符串去存,最后会遇到转义和读取时不匹配的问题,白白增加工作量。
CSV的读写其实很简单:
python复制import csv
def save_data():
with open("students.csv", "w", newline="", encoding="utf-8-sig") as f:
writer = csv.writer(f)
writer.writerow(["name", "sno", "score"])
