核心篇 · Core
lv.2 核心
kp-012
迭代器协议
1. 一句话定义
可迭代对象实现 __iter__ 返回迭代器;迭代器额外实现 __next__ 逐个吐值,耗尽抛 StopIteration——for 循环、解包、推导式全部建立在这套协议上。
2. 为什么重要
这是 Python"鸭子类型"(kp-019)的经典舞台:不关心对象是什么类型,只关心它会不会 next()。理解协议后,for/推导式/生成器/asyncio 看起来不再是四个孤立特性,而是同一思想的四层展开。
3. 前置知识
kp-006(for 循环的表层用法)。
4. 核心概念
- Iterable(可迭代):有
__iter__;可反复迭代(每次返回新迭代器)。 - Iterator(迭代器):有
__iter__(返回自身)+__next__;一次性,耗尽即空。 - 关系:
list是 iterable 不是 iterator;调用iter(list)得到它的 iterator。
5. 原理与机制
python
it = iter([10, 20])
next(it) # 10
next(it) # 20
next(it) # StopIteration
# for x in obj 等价于:
_it = iter(obj)
while True:
try:
x = next(_it)
except StopIteration:
break
... # 循环体自定义迭代器:
python
class Countdown:
def __init__(self, n): self.n = n
def __iter__(self): return self
def __next__(self):
if self.n <= 0:
raise StopIteration
self.n -= 1
return self.n + 1内置工具:zip 并行迭代(短者止)、enumerate 带下标、reversed、iter(callable, sentinel) 的哨兵模式。
6. 关键事实(模型/图示)
text
Iterable ──iter()──► Iterator ──next()──► 值 … ──► StopIteration
▲
for / zip / list() / 解包 / max min sum 全都在调这一对函数zip 与 map 返回的就是迭代器——"惰性"在标准库无处不在。
7. 直观类比
iterable 是一本书(可以反复从第一页读起),iterator 是书签:它记住读到哪了,只能前进不能后退,读完(StopIteration)这本书签就作废。你不会对书签说"翻回第一页"——那要重新开一本(重新 iter())。
8. 实例与案例
python
names = ["a", "b"]; scores = [90, 80]
for n, s in zip(names, scores):
print(n, s)
# 迭代器的一次性坑
it = iter([1, 2, 3])
sum(it) # 6
sum(it) # 0 !已耗尽9. 常见误区
- 对迭代器二次消费(上例)—— 判断与遍历共用同一个生成器/迭代器是经典 bug;要复用先
list()具体化。 - 把"可 for"与"是 list"画等号 —— 文件对象、
dict.keys()、zip结果都可 for,但不是 list,有的只能遍历一次。 - 以为
next()越界返回 None —— 抛StopIteration;可用next(it, default)提供默认值。
10. 自测题
- list 是 iterator 吗?如何得到它的 iterator?
zip([1,2],[3,4,5])会产出几组?为什么?- 自己写一个类迭代序列需要实现哪些方法?
参考答案
- 不是;
iter(lst)。 - 2 组;zip 按最短的可迭代长度停止。
__iter__(返回自身或新迭代器)与__next__(吐值并最终抛 StopIteration)。
11. 与其他知识点的关系
12. 延伸阅读
- Python 官方文档:Iterator Types / Glossary: iterator, iterable