第15章-综合练习:词频统计与成绩管理


前四天我们学了四样装数据的容器:字符串(一句话)、列表(一串东西)、字典(有名字的数据)、集合(去重)。今天不学新东西,把四样全用上,写两个完整程序:词频统计和成绩管理。

为什么专门安排这一天?因为真实工作里没有一个程序是"只用一种容器"写出来的——都是容器 + 循环 + 判断组合出来的。今天练的不只是代码,更是一种干活方式:先自己写,卡住了问 AI,但动手必须自己来。做完今天的练习,你就能挺直腰板说:我独立写出了有真实用途的小程序,而且我知道怎么跟 AI 一起干活。

先把四个容器摆在一起

写综合练习前,把本周的容器放一起对比一遍,脑子里得有这张表:

容器 写法 特点 什么时候用 今天的例子
字符串 "你好" 一串文字,只能读不能改 存文字、处理文字 输入的整句话
列表 [1, 2, 3] 有序、能增删改,靠下标找 一串同类型的东西 拆出来的单词、成绩列表
字典 {"a": 1} 键值对,靠名字找 一个东西的多个属性 词频结果、一个学生
集合 {1, 2, 3} 自动去重、无序 去重、找重复 判断单词有没有重复(了解)

这张表背后有一个核心公式,今天两个程序就是它的最好示范:所有复杂程序 = 容器 + 循环 + 判断。容器装数据,循环过数据,判断处理数据。

今天会用到的方法,先过一遍"代码速查卡":

s = "python is fun"
words = s.split()            # 字符串 → 列表:['python', 'is', 'fun']

cart = []
cart.append("牛奶")           # 列表加元素

count = {}                   # 空字典
count["python"] = 1          # 字典加键值对(不存在就是新增)

students = [{"name": "小明", "score": 92}]
print(students[0]["name"])   # 列表套字典取"一格":小明

for key, value in count.items():    # 遍历字典(键+值)
    print(key, value)

三个地方别弄混:别把"容器"和"类型"搞混——"123" 是字符串,123 是数字,["123"] 是列表,三个完全不同;词频统计里,字典的键是单词、值是次数,这个方向别反了;先想清楚"数据放哪个容器"再动手写——数据结构想清楚了,代码就完成一半。

程序一:词频统计

需求:输入一句话,统计每个词出现几次。

写程序前先拆步骤,这是职业习惯:

  1. 输入一句话(字符串)→ input()
  2. 按空格拆成单词列表 → split()
  3. 遍历每个单词,数次数 → 字典计数(核心逻辑)
  4. 打印结果 → items() 遍历输出

第 3 步的"字典计数"是这个程序的心脏,逻辑只有两条:单词没出现过,给字典加一个键,次数记 1;单词出现过,次数加 1。

text = input("请输入一句话:")
words = text.split()          # 按空格拆成单词列表
result = {}                   # 空字典:单词 → 次数

for w in words:               # 每个单词来一遍
    if w in result:           # 以前记过这个单词?
        result[w] += 1        # 记过:次数加 1
    else:
        result[w] = 1         # 没记过:第一次出现,记 1

for w, count in result.items():
    print(f"{w}: {count} 次")

假设输入 python is fun and python is cool,输出:

请输入一句话:python is fun and python is cool
python: 2 次
is: 2 次
fun: 1 次
and: 1 次
cool: 1 次

这个"字典计数"模式以后到处用,把逻辑讲透:

  • if w in result: 判断的是单词这个键在不在字典里——in 判断键,周三刚学过,这里就用上了。
  • 为什么不能直接 result[w] += 1?因为第一次出现时 result[w] 还不存在,直接加会报 KeyError,所以必须先判断"有没有"。
  • 输入里如果有标点(python, 带逗号),split() 会把 python, 当成一个词——这就是进阶题要解决的问题。

再提三个容易翻车的:统计前先 print(words) 看看拆对了没有,拆错了一切都白搭;单词大小写不同会被当成两个词(Pythonpython),进阶题可以顺手用 lower() 统一;忘写 result = {} 会在 result[w] 时报 NameError,空字典必须先建好。

程序二:成绩管理

需求:存 3 个同学的成绩,算出平均分、最高分、最低分。

同样先拆步骤:

  1. 数据放哪?→ 列表套字典(一个学生一个字典,昨天刚学的表格结构)
  2. 怎么算?→ 把所有成绩抽成一列(数字列表)
  3. 算完怎么输出?→ sum / max / min 加 f-string
students = [
    {"name": "小明", "score": 92},
    {"name": "小红", "score": 85},
    {"name": "小刚", "score": 78},
]

# 第 2 步:抽出所有成绩(普通写法 + 推导式写法都行)
scores = [stu["score"] for stu in students]   # [92, 85, 78]

# 第 3 步:计算并输出
print(f"平均分:{sum(scores) / len(scores)}")   # 平均分:85.0
print(f"最高分:{max(scores)}")                 # 最高分:92
print(f"最低分:{min(scores)}")                 # 最低分:78

# 顺手把每个同学的成绩也打印出来(遍历表格)
for stu in students:
    print(f"{stu['name']}{stu['score']} 分")

输出:

平均分:85.0
最高分:92
最低分:78
小明:92 分
小红:85 分
小刚:78 分

几个"为什么"说清楚:数据用列表套字典存,而不是三个独立变量——因为"一个东西的多个属性"就该用字典,"多个同学"就该用列表,这就是周三讲的选择标准;scores 必须是数字列表才能用 sum / max / min,抽列这一步([stu["score"] for stu in students])就是周四讲的"按列抽数据";平均分是 sum / len(总和 ÷ 个数),写成 len / sum 会得到 0 附近的小数,方向别反。

容易出错的地方,集中在"层"和"类型"上:students[0] 是字典,students[0]["score"] 才是成绩,少一层 ["score"] 会算错或报错;抽列时键名写错(stu["Score"])会报 KeyError——键名和字典里的必须一字不差;想算平均分但抽出的是字符串(比如数据里存了 "92")会报 TypeError——数据存的时候就用数字。

卡住了怎么办:AI 协作五步法

今天允许用 AI,但要用得聪明。原则一句话:独立完成,卡住再问 AI。照着这五步走:

步骤 做什么 举例
1. 先自己写 能写多少写多少,哪怕只有空壳 text = input(...)result = {}
2. 说出卡在哪 把"想做什么 + 卡在哪"发给 AI "词频统计里,怎么判断单词第一次出现"
3. 看思路别抄代码 让 AI 先讲思路,自己动手写 "先别给代码,讲思路"
4. 跑不通就贴报错 把完整报错信息发给 AI KeyError: 'python' 整段报错
5. 跑通了再改造 跑通基础版,再让 AI 帮加功能 "加上去掉标点符号"

第 1 步说的"空壳",长这样——求助 AI 时,自己先写到这个程度再求助:

text = input("请输入一句话:")
words = text.split()
result = {}
for w in words:
    # 卡在这里:不知道怎么数次数
    pass          # pass 表示"先占个位置"
for w, count in result.items():
    print(f"{w}: {count} 次")

三条规矩记牢:别一上来就让 AI 写完整代码——先把需求和自己的半成品发过去,AI 给的答案更贴合你的思路;报错信息要完整复制,别只发"报错了"三个字,AI 看不到你的屏幕;让 AI 干活后一定要自己敲一遍代码,光复制粘贴学不会编程。AI 写的代码必须自己读懂,看不懂就让 AI 加注释或"用普通 for 循环改写",抄完看不懂 = 白练。

随堂练习

练习一(必做):词频统计

独立写出词频统计程序(程序一的完整代码),跑通后换一句更长的英文句子再测一遍,确认每个词的次数都对。

提示:跑不通先 print(words) 看拆分结果,再检查"判断 + 加 1 / 记 1"两条分支。

练习二(必做):成绩管理

独立写出成绩管理程序(程序二的完整代码),然后自己加第 4 个同学,重跑验证平均分、最高分、最低分都对。

提示:加同学用 append;分数用数字不要用字符串,否则 sum 报错。

进阶题(可选):词频统计升级——去掉标点

给词频统计升级:把 .,! 等标点去掉再统计(输入 Hello, world! Hello python. 应该统计出 hello: 2 次 而不是 hello,: 1 次)。

提示:用 replace 把标点替换成空字符串,注意单词大小写要统一(lower());卡住就问 AI,这是今天的进阶挑战。

参考解法(先自己试 20 分钟,再对照):

text = input("请输入一句话:")
# 第一步:去掉标点符号(把每个标点替换成空字符串)
for p in ".,!?,。!?":
    text = text.replace(p, "")

# 第二步:统一成小写,避免 Python 和 python 被当成两个词
text = text.lower()

# 第三步:后面和基础版完全一样
words = text.split()
result = {}
for w in words:
    if w in result:
        result[w] += 1
    else:
        result[w] = 1
for w, count in result.items():
    print(f"{w}: {count} 次")

假设输入 Hello, world! Hello python.,输出:

请输入一句话:Hello, world! Hello python.
hello: 2 次
world: 1 次
python: 1 次

这个进阶程序把本周的知识全用上了:replace 去标点(周一)、lower 统一大小写(周一)、split 拆词(周一)、for 遍历(周二)、字典计数(周三)——五天的知识一个不落。

写不出来时,让 AI 搭把手

场景:成绩管理程序让 AI 写参考实现
提示词:
我是 Python 初学者,正在学字典和列表。我有 3 个学生的成绩,
想存进一个字典列表,然后算出平均分、最高分、最低分。
请帮我写 Python 代码,数据用列表套字典表示,
用普通 for 循环(不要用列表推导式),代码加注释。
场景:词频统计的去标点升级不会做
提示词:
我的词频统计程序能统计单词次数,但输入 "Hello, world!" 时
会把 "Hello," 和 "world!" 当成单词,带标点。我想先去掉标点
再统计,还要统一大小写。请告诉我怎么做,先讲思路再给代码,
代码加注释,用最简单的写法。

常见报错速查

报错信息 什么意思 怎么办
KeyError: 'python' 字典里没有这个键就取值了 先用 in 判断,或用 get();词频统计里"第一次出现"要先记 1
TypeError: unsupported operand type(s) for +: 'int' and 'str' 数字和字符串做了加法 检查抽出来的成绩是不是数字,input 出来的记得 int() 转换
NameError: name 'result' is not defined 变量没定义就使用 检查是不是忘了 result = {} 或拼错了变量名
ValueError: could not convert string to float 把文字转数字失败 确认输入的是数字,或数据里没有混入空字符串

收个尾

本周到此结束。回头看这四天:字符串(一句话)、列表(一串)、字典(有名字的)、集合(去重),所有复杂程序 = 容器 + 循环 + 判断。词频统计的心脏是"计数模式"——if w in result: result[w] += 1 else: result[w] = 1;成绩管理的套路是——列表套字典存数据 → 抽一列成数字列表 → sum / max / min 计算。能独立完成这两个程序,本周目标就算达成。

下周进入函数、模块与文件:这几天的代码都挤在一起,下周学怎么把一段功能包成函数——写好一次,到处调用。学完你就能写出更长的程序而不乱。周末记得休息好,周六见。

本周测评(周六周测说明)

周六周测说明(周六上机,约 40 分钟):

  • 形式:上机操作题,共 4 题,全部在本周所学范围内:
  • 字符串切片与加工(s[0:5]upper()replace() 等)
  • 列表增删改查(append / pop / remove / 下标赋值,遍历打印)
  • 字典增删改查与遍历(get 取值、items() 遍历,判断键是否存在)
  • 集合去重(set(列表) 去重,找出重复数字)
  • 考核要点:操作为主、理论为辅。能不能亲手敲出代码比能不能背概念更重要;每题按"跑通 + 结果正确"给分,完成 60% 即通过
  • 未通过怎么办:周日照常到教室补测,重点补做错题的部分;补测通过同样算达标
  • 复习建议:周六前把第 11~14 章"随堂练习"的题目每题重敲一遍,对着下面的复习清单逐条自查:

  • [ ] 会用切片取字符串 / 列表的一部分

  • [ ] 会列表的增删改查(append / pop / remove / 下标改)
  • [ ] 会字典的增删改查(get / 新增 / 修改 / pop)
  • [ ] 会用 for k, v in 字典.items() 遍历字典
  • [ ] 会用集合去重
  • [ ] 能独立完成词频统计