| Day 7 | 字典与集合 + 阶段一小项目(猜数字 / 成绩统计) |

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 = 0Day 1存答案、存次数
猜数字int(input(...))Day 2字符串转数字才能比较
猜数字guess > targetguess < targetDay 3判断大了还是小了
猜数字if / elif / elseDay 4三路分支:大 / 小 / 对
猜数字while True: + breakDay 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
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇