1 字典 —— 按「名字」查「内容」
是什么?为什么学?
列表用下标(0、1、2…)找元素,记下标很累。字典用键(key)找值(value),就像查电话号码本:按「名字」找到「号码」。为什么零基础必学?因为现实数据几乎都是「成对出现」的——学生的名字对应成绩、菜名对应价格。字典让数据「有名字」,是处理真实数据的核心容器。
底层原理
字典底层是哈希表(hash table):给每个键算一个「哈希值」(类似索引编号),按编号直接定位到值的位置,所以按键查值极快——不管字典有多大,查一次都几乎是瞬间完成。正因为查找依赖哈希值,字典的键必须是不可变类型(字符串、数字、元组),列表可变、算不出稳定哈希,所以不能当键。
术语小词典:哈希值(hash value)就是给键算的一个「索引编号」,像图书馆的书号——按书号直接定位,不用一本本翻。哈希表(hash table)就是用这个原理组织数据的结构。
生活类比
字典像名片夹或工具书:你知道「键」(词条/名字),就能查到「值」(解释/号码)。键是「怎么找」,值是「找到什么」。student["name"] 就像翻到「name」这一页,看到「小明」。
注意事项总结
1 创建字典:
student = {"name": "小明", "age": 18, "score": 92}
print(student["name"]) # 用键取对应的值
print(student["age"])
运行结果:
小明
18
字典用**花括号 {}**,里面是 键: 值 的配对,键和值之间用冒号,一对与一对之间用逗号。
2 键可以是字符串、数字等:
menu = {"拉面": 15, "饺子": 12, "可乐": 4}
print(menu["拉面"]) # 15
print(menu["可乐"]) # 4
易错点
- 错误写法:
student["score"](score 键不存在) → 问题:报KeyError: 'score',程序崩溃 → 正确写法:用student.get("score", "暂无")返回默认值。 - 错误写法:把列表当键:
{[1, 2]: "x"}→ 问题:报TypeError: unhashable type: 'list'→ 正确写法:键用不可变类型(字符串、数字、元组)。 - 错误写法:字典花括号里漏了冒号或逗号:
{"name" "小明"}→ 问题:报SyntaxError→ 正确写法:每个键值对都是键: 值且逗号分隔。
记忆口诀:字典花括号,键值冒号连;按名查内容,键要不可变。
2 字典的增删改查
是什么?为什么学?
字典能随时增、删、改、查——加一条学生信息、改一个成绩、删一道菜。这是字典使用频率最高的部分,几乎每个用字典的程序都离不开。
注意事项总结
1 增删改查速查表:
| 操作 | 写法 | 作用 |
|---|---|---|
| 查 | 字典[键] | 取对应值(键不存在会报 KeyError) |
| 查(安全) | 字典.get(键, 默认值) | 键不存在返回默认值,不报错 |
| 增 / 改 | 字典[键] = 值 | 键存在就改,不存在就新增 |
| 删 | del 字典[键] | 删除某个键值对 |
| 删(安全) | 字典.pop(键, 默认值) | 删除并返回值,键不存在返回默认值 |
2 get 比 [] 更安全:
student = {"name": "小明", "age": 18}
print(student.get("name")) # 小明
print(student.get("score", "暂无成绩")) # 键不存在,返回默认值
运行结果:
小明
暂无成绩
3 增和改——同一个写法:
student = {"name": "小明", "age": 18}
student["score"] = 92 # 键不存在 -> 新增
student["age"] = 19 # 键存在 -> 修改
print(student)
运行结果:
{'name': '小明', 'age': 19, 'score': 92}
4 删——del 和 pop:
menu = {"拉面": 15, "饺子": 12, "可乐": 4}
del menu["可乐"]
removed = menu.pop("饺子", "没有这个菜")
print(removed) # 12
print(menu)
运行结果:
12
{'拉面': 15}
易错点
- 错误写法:
student["score"] = 92以为只能新增 → 问题:如果键已存在会覆盖旧值,不是报错 → 正确写法:想「只新增不覆盖」先if "score" not in student:判断。 - 错误写法:
del menu["可乐"]而可乐不存在 → 问题:报KeyError→ 正确写法:用menu.pop("可乐", None)或先判断。 - 错误写法:确定键存在却还用 get → 问题:不报错但可能悄悄拿到默认值,掩盖 bug → 正确写法:键一定存在用
[](简单直接),可能不存在才用get。
记忆口诀:查用中括号,get 更稳当;赋值即增改,del 删键对。
3 遍历字典
是什么?为什么学?
遍历字典是把字典里的数据「一个个拿出来」处理的方式。统计、打印、汇总时最高频的写法就是遍历——比如把菜单全部打印出来、把所有学生的成绩算一遍。
注意事项总结
1 遍历键:
menu = {"拉面": 15, "饺子": 12}
for key in menu:
print(key)
运行结果:
拉面
饺子
2 遍历值:
menu = {"拉面": 15, "饺子": 12}
for value in menu.values():
print(value)
运行结果:
15
12
3 同时遍历键和值(最常用):
menu = {"拉面": 15, "饺子": 12}
for name, price in menu.items():
print(name, "的价格是", price)
运行结果:
拉面 的价格是 15
饺子 的价格是 12
关键理解:字典.items() 一次给出「键和值」两个东西,所以循环变量要写两个(for name, price in ...)——这正是元组拆包(Day 6)在实战中的应用。
易错点
- 错误写法:
for name, price in menu:(忘了 .items()) → 问题:循环变量只拿到键,拆包会报错或拿到错误数据 → 正确写法:for name, price in menu.items():。 - 错误写法:遍历字典时删除键 → 问题:报
RuntimeError: dictionary changed size during iteration→ 正确写法:先收集要删的键,遍历结束后再删。
记忆口诀:遍历键值用 items,两个变量一起拿;只想要键直接 for,只想要值加 .values。
4 嵌套容器 —— 容器里套容器
是什么?为什么学?
列表和字典可以互相嵌套,组合出非常强大的数据结构。比如「一个班的学生信息」:外层是列表,里面每个元素是一个字典。为什么必学?因为真实数据几乎都是多层结构——学校里有班级、班级里有学生、学生有各项属性,不会嵌套就无法表达真实世界。
注意事项总结
1 列表套字典:
students = [
{"name": "小明", "score": 92},
{"name": "小红", "score": 88},
{"name": "小刚", "score": 75},
]
print(students[0]["name"]) # 先按下标取字典,再按键取值
print(students[1]["score"])
运行结果:
小明
88
2 字典套列表:
class_info = {
"name": "Python 班",
"students": ["小明", "小红", "小刚"],
"scores": [92, 88, 75],
}
print(class_info["name"])
print(class_info["students"][2]) # 先取列表,再按下标
运行结果:
Python 班
小刚
3 遍历嵌套结构(逐个打印学生成绩):
students = [
{"name": "小明", "score": 92},
{"name": "小红", "score": 88},
]
for s in students:
print(s["name"], "考了", s["score"], "分")
运行结果:
小明 考了 92 分
小红 考了 88 分
关键理解:嵌套就是「一层一层剥开」——先按外层容器的取法取出内层容器,再按内层容器的取法取数据。多练几次「剥洋葱」就不难了。
易错点
- 错误写法:
students[0]后忘了再["name"]→ 问题:拿到的是整个字典{'name': '小明', ...},不是名字 → 正确写法:多层访问要层层取:students[0]["name"]。 - 错误写法:访问层级写反:
students["name"][0]→ 问题:students 是列表,不能用键取 → 正确写法:外层是列表用下标,内层是字典用键,看准每一层的容器类型。
记忆口诀:嵌套像洋葱,一层一层剥;外层看类型,下标或键取。
5 集合 —— 自动去重的容器
是什么?为什么学?
集合用花括号 {} 或 set() 创建,特点有两个:元素不重复、顺序不保证。它最常用的场景就是「去重」——统计成绩有几种不同的分值、统计一篇文章出现了哪些词,一行搞定。
底层原理
集合的底层也是哈希表(和字典同源,相当于「只有键没有值」的字典)。正因为按哈希值存储,集合的两个特性由此而来:① 元素重复时,哈希值相同,自动合并——这就是自动去重;② 查找元素用哈希定位而不是逐个比对,所以 值 in 集合 非常快。同时,哈希存储不保证顺序,所以集合没有下标。
生活类比
集合像超市的会员名单:同一个会员只登记一次(自动去重),而且名单不是按登记顺序放的,是按会员编号(哈希值)放的——所以「找一个人快不快」和名单长短无关,但名单没有先后顺序。
注意事项总结
1 创建集合,重复元素自动只剩一个:
colors = {"红", "绿", "红", "蓝", "绿"}
print(colors)
运行结果:
{'红', '绿', '蓝'}(顺序可能不同,但一定不重复)
2 列表转集合去重:
nums = [1, 2, 2, 3, 3, 3, 4]
unique = set(nums)
print(unique) # {1, 2, 3, 4}
back_to_list = list(unique) # 需要时再转回列表
运行结果:
{1, 2, 3, 4}
[1, 2, 3, 4]
3 集合常用操作:
a = {1, 2, 3}
b = {3, 4, 5}
print(a | b) # 并集:合并去重
print(a & b) # 交集:两边都有
print(a - b) # 差集:a 有 b 没有
运行结果:
{1, 2, 3, 4, 5}
{3}
{1, 2}
易错点
- 错误写法:
{1, 2, 3}和{"a": 1}分不清 → 问题:都是花括号,前者是集合、后者是字典 → 正确写法:看有没有冒号——有冒号是字典,没有是集合。 - 错误写法:
colors[0]想取集合第一个元素 → 问题:集合没有顺序、不能按下标取,报TypeError→ 正确写法:需要按下标取就先list(colors)转列表。 - 错误写法:
set([1, [2]])往集合里放列表 → 问题:报TypeError: unhashable type: 'list'→ 正确写法:集合元素必须是不可变类型。
记忆口诀:集合花括号,自动去重复;判断在不在,快得像飞;没有顺序无下标,要排序就转列表。
6 阶段一小项目 —— 猜数字游戏 + 成绩统计
今天是阶段一收官日,两个项目把 Day 1~7 的知识串成完整的程序。先自己想,再看参考代码——项目做不出来往往不是今天的问题,而是前面某天的基础没打牢。
项目 1:猜数字游戏 —— 程序随机生成 1~100 的整数,用户循环猜,提示「大了/小了」,猜中显示次数。
# 猜数字游戏
import random
target = random.randint(1, 100)
guess_count = 0
print("我想好了一个 1~100 之间的数字,你来猜猜看!")
while True:
guess = int(input("请输入你的猜测:"))
guess_count = guess_count + 1
if guess > target:
print("太大了,再小一点")
elif guess < target:
print("太小了,再大一点")
else:
print("恭喜你!猜对了,答案就是", target)
print("你一共猜了", guess_count, "次")
break
项目 2:成绩统计脚本 —— 把 N 个学生的成绩放进列表,统计平均分、最高分、最低分。
# 成绩统计脚本
n = int(input("请输入学生人数:"))
scores = []
for i in range(n):
score = float(input(f"请输入第 {i + 1} 个学生的成绩:"))
scores.append(score)
average = sum(scores) / len(scores) # sum() 是内置的求和函数
highest = max(scores) # max() 求最大值
lowest = min(scores) # min() 求最小值
print("成绩单:", scores)
print("平均分:", average)
print("最高分:", highest)
print("最低分:", lowest)
两个项目的知识点拆解:
| 项目 | 用到的知识点 | 来自哪一天 | 作用 |
|---|---|---|---|
| 猜数字 | target = random.randint(1, 100)、guess_count = 0 | Day 1 | 存答案、存次数 |
| 猜数字 | int(input(...)) | Day 2 | 字符串转数字才能比较 |
| 猜数字 | guess > target、guess < target | Day 3 | 判断大了还是小了 |
| 猜数字 | if / elif / else | Day 4 | 三路分支:大 / 小 / 对 |
| 猜数字 | while True: + break | Day 5 | 反复猜直到猜中 |
| 成绩统计 | for i in range(n) | Day 5 | 循环 N 次逐个输入成绩 |
| 成绩统计 | scores = []、scores.append(score) | Day 6 | 收集所有成绩 |
| 成绩统计 | sum() / max() / min() / len() | Day 6 扩展 | 求和、最大、最小、个数 |
想一想:去掉最高分和最低分后的平均分怎么算?思路:先 scores.sort() 排序,再 scores[1:-1] 切片去掉首尾,最后 sum(middle) / len(middle)——把 Day 6 的「排序 + 切片」和 Day 3 的「求平均」串在一起。
今日总结
字典用 键: 值 存数据,字典[键] 取值,get() 更安全(键不存在返回默认值)
for k, v in 字典.items() 是遍历字典最常用的写法
列表和字典可以嵌套组合,访问时「一层层剥开」——外层看容器类型
集合自动去重,适合「去重 + 快速判断在不在」;没有顺序、不能按下标取
字典的键必须是不可变类型(列表不行,元组可以)
阶段知识地图:变量 → 数据类型 → 运算符 → 条件 → 循环 → 列表元组 → 字典集合,一环扣一环
项目拆解能力:能把「猜数字」「成绩统计」拆成「用到了哪些知识点」的清单
| 报错 | 原因 | 修复 |
|---|---|---|
KeyError: 'xxx' | 用 字典[键] 取值,但键不存在 | 改用 字典.get(键, 默认值),或先 if 键 in 字典 判断 |
SyntaxError: invalid syntax | 字典花括号里漏了冒号或逗号 | 检查每个键值对是否都是 键: 值 且逗号分隔 |
TypeError: unhashable type: 'list' | 试图把列表当作字典的键或放进集合 | 键和集合元素必须是不可变类型(字符串、数字、元组),不能用列表 |
ValueError: min() arg is an empty sequence | 对空列表调用 max/min/sum | 先判断列表是否为空再统计 |
NameError: name 'random' is not defined | 用了 random 但忘了导入 | 文件开头写 import random |