> **GESP等级：三级 | 考级考点：GESP Python 三级**

# 第07节 字典 dict —— 增删改查 {key: value}
**课时：** 1课时（约60分钟）
**目标学生：** 已掌握集合基本操作（第1、2节），尚未接触字典
**GESP考点：** #40 字典基本操作（创建、访问、修改、删除）

---

## 教学目标

1. **理解字典的存在意义**：解决"索引无意义"的问题，用有意义的键代替数字下标
2. **掌握字典的创建方式**：`{}` 字面量、`dict()` 构造、空字典
3. **掌握 `d[key]` 取值与 `get(key)` 安全取值**：理解两者在 key 不存在时的区别
4. **掌握增改操作**：`d[key] = value` —— 有则改、无则增
5. **掌握删除操作**：`pop(key)` 删除并返回值 vs `del d[key]` 直接删除 vs `clear()` 清空
6. **理解键的约束条件**：键必须是不可变类型（字符串、数字、元组），列表不能做键

---

## 教学重难点

| 类型 | 内容 |
|------|------|
| 重点 | 字典的 4 种核心操作：增（赋值新 key）、删（pop/del/clear）、改（赋值已有 key）、查（d[key] / get()） |
| 难点 | `d[key]` 与 `get(key)` 的区别、`pop()` 删除并返回值 vs `del` 不返回、键的不可变约束 |
| 易错点 | 字典用 `{}` 误写成 `[]`、键字符串忘加引号、遍历时混淆字典与列表、`get()` 返回值忘赋值 |

---

## 教学过程

### 第一部分：导入——为什么需要字典？（00:00-10:00）

**场景提问：**

> "我想知道'红色'的 RGB 值是什么，用列表怎么写？"

```python
colors_list = ["#FF0000", "#0000FF", "#00FF00"]
# colors_list[0] 是红色还是蓝色？根本记不住！
```

**制造痛点：**
- `colors_list[0]` —— 0 号是红色还是蓝色？谁记得住！
- 索引 0/1/2 没有任何**语义**，只是位置编号

**引出字典：**

```python
colors_dict = {"red": "#FF0000", "blue": "#0000FF", "green": "#00FF00"}
print(colors_dict["red"])   # 直接说"给我红色的 RGB"——多直观！
```

**记忆钩子：**
> 列表 = 按座位号找人（0号、1号、2号...）
> 字典 = 喊名字找人（"小红！"）

**引导问答：**
- 列表用 `[]`，字典用什么？→ `{}`
- 列表里元素用逗号隔开，字典里呢？→ 键和值用冒号 `:` 连接，键值对之间用逗号
- 键能不能是数字？→ 可以！键可以是字符串、数字、元组（不可变类型）

---

### 第二部分：知识点讲解——字典增删改查（10:00-30:00）

#### ① 创建字典（3分钟）

```python
# 方式一：字面量
d = {"red": "红", "blue": "蓝", "green": "绿"}

# 方式二：空字典
e = {}

# 方式三：dict() 构造
f = dict(red="红", blue="蓝")
```

**要点：**
- `{}` 花括号像一本翻开的字典
- 键(`key`)在冒号左边，值(`value`)在冒号右边
- 键必须是不可变类型（字符串、数字、元组）

#### ② 查——`d[key]` 取值（3分钟）

```python
d = {"red": "红色", "blue": "蓝色"}
print(d["red"])        # → "红色"
# print(d["green"])    # KeyError！没有这个 key 会报错
```

**安全取值：`get(key, 默认值)`**

```python
print(d.get("red"))          # → "红色"
print(d.get("green"))        # → None（不报错！）
print(d.get("green", "没有")) # → "没有"（找不到时返回默认值）
```

**对比强调：**
> `d["red"]` = 直接翻到"red"那页，没有就**摔书报错**
> `d.get("red")` = 先看看有没有"red"，没有就**温和地说 None**

#### ③ 增/改——`d[key] = value`（3分钟）

```python
d = {"red": "红色"}

d["red"] = "红彤彤"    # 改：key "red" 已存在 → 修改值
d["blue"] = "蓝色"     # 增：key "blue" 不存在 → 添加新键值对
```

**口诀：**
> **"有则改、无则增"** —— 同一个语法，两种行为

#### ④ 删——pop / del / clear（4分钟）

**`pop(key)` —— 删除并返回值**

```python
val = d.pop("red")     # 删除 "red" 这一对，val = "红色"
print(d)               # {"blue": "蓝色"}
print(val)             # "红色" —— pop 把值还给你了
```

**`del d[key]` —— 直接删除**

```python
del d["blue"]          # 删了就没了，不返回值
# print(d["blue"])     # KeyError！已经删了
```

**`clear()` —— 全部清空**

```python
d.clear()              # 字典变成空 {}
```

**口诀：**
> **"pop 弹出来还给你，del 直接扔，clear 全倒掉"**

#### ⑤ 键的约束条件（2分钟）

```python
d = {
    "name": "小明",     # 字符串做键 ✓
    1: "数字一",         # 数字做键 ✓
    (1, 2): "元组",     # 元组做键 ✓
    # ["a", "b"]: "列表"  # 列表做键 → TypeError！
}
```

**为什么列表不行？**
> 字典靠键的**哈希值**查找。列表可以变（append/remove），变了哈希值就变了，字典就找不到它了。
> 钥匙（键）不能变形，变形了就开不了锁。

**记忆钩子：**
> **"键要不变，值随便变。字符串、数字、元组可以当键，列表不行。"**

---

### 第三部分：演示——颜色字典实战（30:00-40:00）

讲师现场逐行运行，每敲一行问一句"这行做了什么？"

```python
# 第1步：创建颜色字典
colors = {
    "red": "#FF0000",
    "blue": "#0000FF",
    "green": "#00FF00"
}

# 第2步：查
print(colors["red"])       # → #FF0000

# 第3步：增
colors["yellow"] = "#FFFF00"
print(colors)

# 第4步：改
colors["red"] = "#FF2222"  # 改红色为另一种红
print(colors)

# 第5步：删
val = colors.pop("blue")
print(f"删除了 blue，它的值是 {val}")
print(colors)

del colors["yellow"]
print(colors)

# 第6步：安全取值 vs 直接取值
print(colors.get("black"))          # → None
# print(colors["black"])            # → KeyError（取消注释试试）

# 第7步：遍历
for k, v in colors.items():
    print(f"{k} → {v}")

# 第8步：清空
colors.clear()
print(colors)                       # → {}
```

**教师巡堂重点关注：**
- 学生是否把 `{}` 写成了 `[]` 或 `()`
- 学生是否在键字符串上忘了加引号
- 学生是否把 `:` 写成了 `=`
- `get()` 返回值是否被正确接住（赋值给变量）

---

### 第四部分：实操练习（40:00-55:00）

按 `04_dict_practice.py` 文件依次完成，共 4 个必做练习 + 2 个挑战。

**练习1：填空——字典增删改查（10分钟）**

补全 `___`，练习创建/读取/修改/删除的基本操作。重点观察：
- `colors[key]` 取值语法是否正确
- 赋值增改是否写对了
- pop 和 del 的区别

**练习2：get() 安全取值（8分钟）**

对比 `d[key]` 和 `get(key)` 在 key 不存在时的行为差异。
- 让学生亲眼看到 `d["小李"]` 报 KeyError
- 再用 `get("小李")` 对比——返回 None，不报错
- 演示 `get("小李", 0)` 自定义默认值

**练习3：用字典管 turtle 颜色名→中文名（10分钟）**

遍历颜色字典，用 turtle 画出每种颜色的色条并标注中文名。
- 强调 `for eng, chn in color_map.items()` 的双变量遍历
- 键（英文名）传给 `t.color()`，值（中文名）传给 `t.write()`

**练习4：RGB 颜色查询器（7分钟）**

用户输入颜色英文名，程序用 `get()` 从字典中查找 RGB 值并输出。
- 实际体验字典的"键→值"映射
- `get()` 找不到时返回"未知颜色"

**挑战练习（有余力的学生做）：**
- ⭐ 挑战1：用字典统计单词中每个字母的出现次数
- ⭐⭐ 挑战2：中文→英文颜色翻译器（翻转字典的键和值思路）

---

### 第五部分：小测与总结（55:00-60:00）

**小测题目：**

1. `d.get("red")` 和 `d["red"]` 有什么区别？
   - A. 完全一样
   - B. `d.get("red")` 不报错，`d["red"]` 找不到 key 时报错  ← 正确答案
   - C. `d["red"]` 更快
   - D. `d.get("red")` 只能用于字符串键

2. 下面哪个操作是**添加**新键值对？
   ```python
   d = {"a": 1}
   ```
   - A. `d["a"] = 2`
   - B. `d["b"] = 2`   ← 正确答案（"b" 原来不存在）
   - C. `d.pop("a")`
   - D. `d.clear()`

3. `pop("red")` 和 `del d["red"]` 的区别是什么？
   - A. 没区别
   - B. `pop` 会返回值，`del` 不返回值  ← 正确答案
   - C. `del` 会返回值，`pop` 不返回值
   - D. `pop` 只能用在字符串键上

4. 判断：字典的键可以用列表吗？
   - 答：不可以。列表可变，哈希值会变，字典要求键不可变。

5. 补全代码：创建一个空字典 `d`，然后添加 `"name": "Tom"`。
   ```python
   d = ____          # 空字典
   d[____] = ____   # 添加 name → Tom
   ```
   答案：`d = {}`，`d["name"] = "Tom"`

**记忆钩子回顾：**
> **"字典 = 查字典，key 查 value，键不可变值可以变"**
> **"有则改、无则增"**
> **"pop 弹出来还给你，del 直接扔，clear 全倒掉"**

---

## 板书设计

```
┌──────────────────────────────────────────────────────────┐
│  第07节 字典 dict —— {key: value}                          │
│                                                          │
│  创建：d = {"red":"红", "blue":"蓝"}                      │
│         e = {}         f = dict(red="红")                │
│                                                          │
│  ┌───────┬──────────────────────┬─────────────────────┐  │
│  │ 操作  │ 写法                  │ 说明                │  │
│  ├───────┼──────────────────────┼─────────────────────┤  │
│  │ 查    │ d["key"]             │ 没有就 KeyError      │  │
│  │       │ d.get("key", 默认)   │ 没有返回 None/默认   │  │
│  │ 增/改 │ d["key"] = 新值      │ 有→改 无→增          │  │
│  │ 删    │ d.pop("key")         │ 删了返回值            │  │
│  │       │ del d["key"]         │ 删了不返回值          │  │
│  │       │ d.clear()            │ 全部清空              │  │
│  └───────┴──────────────────────┴─────────────────────┘  │
│                                                          │
│  键：必须不可变（str/int/tuple）                           │
│  值：随便（可变不可变都行）                                 │
│                                                          │
│  记忆："有则改、无则增" / "pop 弹，del 扔，clear 倒"       │
└──────────────────────────────────────────────────────────┘
```

---

## 常见错误预警

| 错误写法 | 正确写法 | 说明 |
|---------|---------|------|
| `d = {red: "红"}` | `d = {"red": "红"}` | 键是字符串要加引号 |
| `d["red"] = ` 忘写值 | `d["red"] = "红色"` | 赋值要完整 |
| `d.get("red")` 忘赋值 | `val = d.get("red")` | get 返回的值要接住 |
| `d("red")` 用圆括号 | `d["red"]` 用方括号 | 字典用 `[]` 不是 `()` |
| `d["red"]` 写反键值 | `d["red"]` | 用键查值，不是用值查键 |
| 键用列表 `[1,2]` | 用元组 `(1,2)` | 列表可变不能当键 |

---

## 课后反思

- 学生是否能理解"有则改、无则增"的同一个赋值语法？
- `d[key]` 和 `get(key)` 的区别是否通过 KeyError 亲身体验到了？
- `pop()` 返回值的特性是否和 `del` 区分清楚？
- 是否有学生问"字典和列表什么时候用哪个"？——这是好问题，说明在思考
- 是否有人尝试把列表当键并看到了 TypeError？这个错误本身是最好的教学
