# 知识库

# 2.2.3 可迭代对象的遍历方法

Python 中的许多内置函数会返回可迭代对象，因此遍历可迭代对象是一种常见操作。字符串、列表、元组、集合、字典以及 `range()`、`map()`、`zip()` 的返回值，都可以用 `for...in` 依次访问其中的每个元素。语法为 `for element in iterable:`：`element` 代表当前元素，`iterable` 是可迭代对象。需要注意：`map()`、`zip()` 的返回值本身不是列表，直接打印往往看不到序列内容，必须先用 `list()` 转换成列表再输出。

内置函数 `map()` 接受两个参数：一个函数和一个可迭代对象。它将函数应用于可迭代对象中的每个元素，并返回一个新的可迭代对象，其元素为函数作用的结果。例如：

```python
chengji = ['87', '95', '76', '84']
mapped = map(int, chengji)
print(list(mapped))
```

输出为 `[87, 95, 76, 84]`，相当于把每个成绩字符串转换成整数。内置函数 `zip()` 接收两个或多个可迭代对象作为参数，将对应位置的元素配对形成一个元组，并把这些元组作为可迭代对象的元素返回。例如 `names = ['Alice', 'Bob', 'Charlie']` 与 `scores = [85, 92, 78]`，`list(zip(names, scores))` 得到 `[('Alice', 85), ('Bob', 92), ('Charlie', 78)]`。

Python 遍历可迭代对象有三种方法。第一，用 `for...in` 直接遍历元素，适合只关心值、不关心位置的统计与筛选。例如例 2-7：求一个长度为 100 的随机整数列表中 3 的倍数有多少个，循环变量依次取每个元素 `v`，判断 `v % 3 == 0` 即可计数。第二，使用 `enumerate()`。仅用 `for...in` 能够访问全部元素，但很难掌握每个元素的索引；`enumerate()` 在遍历时同时获取索引和值，返回包含二者的元组，常用于需要同时访问元素及其索引的场景。例如例 2-8：一个列表保存 50 名学生的成绩，输出序号与成绩可用 `for i, v in enumerate(a): print(i+1, v)`。因为第一个元素的索引是 0，给它加 1 以表示学号。第三，依次遍历可迭代对象的索引，用 `while` 和 `for...in` 均可，常见写法是 `for i in range(len(a))`。当必须修改原列表中的元素时，应采用这种方法。

常见坑是：在用 `for...in` 或 `enumerate()` 时，修改遍历的变量不能作用于原来的列表。例 2-9 要求将一个整数列表中的每个元素变成原来的 2 倍。若写成 `for v in a: v *= 2`，循环之前和之后输出的列表相同，原因是 `v *= 2` 只把变量 `v` 变成了原来的 2 倍，并没有改变列表中的元素。正确做法是用 `len()` 计算列表长度，用 `range()` 生成代表索引的可迭代对象：`for i in range(len(a)): a[i] *= 2`。此外，不要把 `enumerate` 得到的 0 起始索引直接当作序号，也不要忘记将 `map`、`zip` 的结果转换成列表后再查看内容。

## 关键要点
- 许多内置函数返回可迭代对象，遍历是常见操作；`for element in iterable:` 依次访问每个元素。
- `map(函数, 可迭代对象)`：把函数作用于每个元素，返回新的可迭代对象；常用 `list()` 查看内容。
- `zip(可迭代对象1, 可迭代对象2, ...)`：将对应位置的元素配对成元组，返回可迭代对象。
- 三种遍历方法：① `for...in` 直接遍历元素；② `enumerate()` 同时得到索引和值；③ 依次遍历索引（`while` 或 `for i in range(len(a))`）。
- `enumerate()` 的第一个元素索引为 0；作序号、学号时通常写 `i+1`。
- 用 `for...in` 或 `enumerate()` 时，修改循环变量不能改变原列表；要改原列表须通过索引，如 `a[i] *= 2`。
