# 教案：第05节 —— 复合嵌套（上）

---

## 元信息

| 项目 | 内容 |
|------|------|
| **课程编号** | G4_第05节 |
| **GESP等级** | **四级**（GESP Python 四级考点） |
| **适用年龄** | 11-14 岁（编程高手阶段） |
| **核心知识点** | 列表套字典、字典套列表、多层索引访问、双层推导式 |
| **记忆钩子** | 列表套字典像表格 字典套列表像目录 多层索引一层层剥开 推导式两重循环 |
| **身体锚点** | ① 外层（大圈手） ② 内层（小圈手） ③ 索引（逐层指） |

---

## 课程目标

1. **掌握** 列表嵌套字典的创建与访问
2. **掌握** 字典嵌套列表的创建与访问
3. **熟练** 使用多层索引从嵌套结构中提取数据
4. **运用** 双层推导式处理嵌套数据

---

## 五段式 60 分钟教学流程

---

### 第一段：导入（00:00 - 10:00）—— 数据也有俄罗斯套娃

#### 教师活动

| 时间 | 活动内容 | 教学方式 |
|------|---------|---------|
| 0-3min | 拿出俄罗斯套娃，一层层打开：数据也可以一层套一层！ | 实物演示 |
| 3-6min | 想想一个班级的花名册：多位学生各有姓名、年龄、成绩 | 生活场景 |
| 6-10min | 展示嵌套结构的威力：一条变量表示一个复杂对象 | 目标宣布 |

#### 导入代码

```python
students = [
    {"name": "小明", "age": 10, "score": 95},
    {"name": "小红", "age": 11, "score": 88},
    {"name": "小刚", "age": 10, "score": 92},
]
print(students[0]["name"])    # 小明
print(students[1]["score"])   # 88
```

#### 生活类比

列表套字典 = 花名册：列表是第几个人，字典是这个人的信息。
字典套列表 = 成绩单：字典键是科目，值是历次成绩的列表。

#### 身体锚点

> **【身体锚点 — 嵌套结构】**
> 左手大圈（外层容器），右手小圈（内层容器）。
> 从外到内一层层访问，先找到外层，再进到内层。
> 手指逐层点：列表到字典到值，字典到列表到元素。

---

### 第二段：知识点精讲（10:00 - 30:00）

#### 2.1 列表套字典（7min）

```python
# 方式一：直接创建
students = [
    {"id": 1, "name": "小明", "scores": [95, 92, 98]},
    {"id": 2, "name": "小红", "scores": [88, 90, 85]},
    {"id": 3, "name": "小刚", "scores": [92, 94, 91]},
]

# 访问第一个学生
s1 = students[0]
print(s1["name"])             # 小明

# 访问第二个学生的第一次成绩
print(students[1]["scores"][0])  # 88
```

**访问路径图示：**
```
students  [0]    ["name"]      "小明"
  列表     索引    字典键        值
students[0]["name"]
```

#### 2.2 字典套列表（6min）

```python
# 字典的值可以是列表
class_scores = {
    "小明": [95, 92, 98],
    "小红": [88, 90, 85],
    "小刚": [92, 94, 91],
}

# 字典的值可以是字典（多层嵌套）
class_info = {
    "class_name": "Python 高级班",
    "teacher": "张老师",
    "students": [
        {"name": "小明", "age": 10},
        {"name": "小红", "age": 11},
    ],
    "schedule": {
        "Monday": "14:00-15:30",
        "Wednesday": "14:00-15:30",
    }
}

# 访问小明的最新成绩
ming_last = class_scores["小明"][-1]
print(ming_last)               # 98

# 多层嵌套访问
print(class_info["schedule"]["Monday"])    # 14:00-15:30
print(class_info["students"][0]["name"])   # 小明
```


#### 2.3 多层索引访问技巧（4min）

```python
data = {
    "school": {
        "classes": [
            {
                "name": "A班",
                "students": [
                    {"name": "小明", "scores": {"math": 95, "eng": 88}},
                    {"name": "小红", "scores": {"math": 92, "eng": 90}},
                ]
            },
        ]
    }
}

# 从最外层开始，一层层剥开
school = data["school"]
first_class = school["classes"][0]
first_student = first_class["students"][0]
math_score = first_student["scores"]["math"]  # 95

# 或者一行写完
score = data["school"]["classes"][0]["students"][0]["scores"]["math"]
print(score)  # 95
```

#### 2.4 双层推导式（3min）

```python
# 列表嵌套字典的推导式
names = [s["name"] for s in students]
print(names)  # ['小明', '小红', '小刚']

all_scores = [score for s in students for score in s["scores"]]
print(all_scores)  # [95, 92, 98, 88, 90, 85, 92, 94, 91]

# 字典嵌套列表的推导式
all_grades = [score for scores in class_scores.values() for score in scores]

# 找出所有超过 95 的成绩
high_scores = [score for scores in class_scores.values() for score in scores if score > 95]
print(high_scores)  # [98, 97, 99, 100]
```

**双重推导式结构解析：**
```python
[ expression for outer_item in outer_iterable for inner_item in inner_iterable ]

# 等价于嵌套 for 循环
result = []
for outer_item in outer_iterable:
    for inner_item in inner_iterable:
        result.append(expression)
```

---

### 第三段：演示（30:00 - 40:00）

#### 演示 1：班级成绩管理系统

```python
classroom = {
    "name": "Python 进阶班",
    "teacher": "王老师",
    "students": [
        {"name": "小明", "scores": {"py": 95, "math": 92, "eng": 88}},
        {"name": "小红", "scores": {"py": 88, "math": 90, "eng": 85}},
        {"name": "小刚", "scores": {"py": 92, "math": 94, "eng": 91}},
        {"name": "小丽", "scores": {"py": 97, "math": 99, "eng": 100}},
    ]
}

py_scores = [(s["name"], s["scores"]["py"]) for s in classroom["students"]]
py_scores.sort(key=lambda x: x[1], reverse=True)
for rank, (name, score) in enumerate(py_scores, 1):
    print(f"第{rank}名: {name} {score}分")
```

#### 演示 2：购物车数据结构

```python
cart = [
    {"item": "苹果", "price": 5, "qty": 3},
    {"item": "香蕉", "price": 3, "qty": 2},
    {"item": "牛奶", "price": 18, "qty": 1},
]
total = sum(item["price"] * item["qty"] for item in cart)
print(f"购物车共 {len(cart)} 件商品，总价: {total} 元")
most_expensive = max(cart, key=lambda x: x["price"] * x["qty"])
print(f"最贵的商品: {most_expensive['item']}")
```

#### 演示 3：双层推导式对比

```python
# 普通双层 for 循环
result1 = []
for scores in class_scores.values():
    for score in scores:
        if score > 90:
            result1.append(score)

# 双层推导式（一行搞定）
result2 = [score for scores in class_scores.values() for score in scores if score > 90]
# 两种方式结果相同
```

---

### 第四段：实操练习（40:00 - 55:00）

#### 练习 1：创建嵌套结构（5min）

```
题目：创建列表套字典结构，存储 3 本书的信息
      每本书有：书名、作者、价格
```

**参考答案：**
```python
books = [
    {"title": "Python入门", "author": "张三", "price": 45},
    {"title": "数据结构", "author": "李四", "price": 52},
    {"title": "算法导论", "author": "王五", "price": 68},
]
```

#### 练习 2：多层索引访问（5min）

```
题目：从以下嵌套结构中提取小丽的数学成绩
data = {
    "grade": "五年级",
    "classes": {
        "A班": {"teacher": "张老师"},
        "B班": {"teacher": "李老师"},
    },
    "scores": {"小丽": {"math": 98, "eng": 95}},
}
```

**答案：** data["scores"]["小丽"]["math"] 结果为 98

#### 练习 3：双层推导式（5min）

```
题目：matrix = [[1,2,3], [4,5,6], [7,8,9]]
      用双层推导式提取所有大于 5 的数字
```

**参考答案：**
```python
matrix = [[1,2,3], [4,5,6], [7,8,9]]
result = [num for row in matrix for num in row if num > 5]
print(result)  # [6, 7, 8, 9]
```



### 第五段：小测（55:00 - 60:00）

#### 题目 1（选择）
students[0]["name"] 中，students 是什么类型？
A. 字典
B. 列表
C. 列表套字典
D. 字典套列表

**答案：C**

#### 题目 2（选择）
双层推导式的等价写法是？
A. 单层 for 循环
B. 双层 for 循环
C. 三层 for 循环
D. while 循环

**答案：B**

#### 题目 3（选择）
data["school"]["classes"][0]["students"][0]["scores"]["math"] 访问的是什么？
A. 学校名
B. 班级名
C. 第一个学生的数学成绩
D. 所有学生的平均分

**答案：C**

#### 题目 4（填空）
字典套列表的访问形式：先通过 ____ 找到键，再通过 ____ 找到元素位置。

**答案：** 键、索引

#### 题目 5（简答）
什么时候应该用列表套字典而不是字典套列表？

**答案：** 数据是有序的一组对象且每个对象有多个属性时用列表套字典（如学生花名册）；数据是按类别划分的集合时用字典套列表（如班级成绩单）。

---

## 板书设计

```
+-------------------------------------------------------+
|       第05节 复合嵌套（上）                             |
+-------------------------------------------------------+

  列表套字典：（有序的对象集合）
  [ {"key1": val1, "key2": val2}, {"key1": val3, ...} ]
  访问: list[idx]["key"]

  字典套列表：（分类的数据集合）
  { "key1": [val1, val2], "key2": [val3, val4] }
  访问: dict["key"][idx]

  双层推导式：
  [ expr for outer in outer_list for inner in outer ]

  记忆钩子：
  列表套字典像表格 字典套列表像目录
  多层索引一层层剥开 推导式两重循环
---

## 课后延伸

| 项目 | 内容 |
|------|------|
| 课后练习 | 课后练习_第05节.md |
| 预习内容 | 第05节 复合嵌套（下） |
| 拓展挑战 | 构建包含三级嵌套（学校-班级-学生）的数据结构 |
| 家长沟通 | 今天学习复杂数据嵌套，孩子能组织多层数据 |

---

## 教学反思

| 维度 | 记录 |
|------|------|
| 学生掌握率 | 预计 60% 学生能独立编写嵌套结构 |
| 常见困惑 | 多层索引容易搞混层数，需要用缩进辅助理解 |
| 改进方向 | 增加安全访问模式的练习 |
| 备注 | 下节课继续复合嵌套的进阶内容 |
```
