欢迎来到 Python 学习计划的第 65 天!🎉
恭喜你完成了 异常与文件模块(第 57-64 天)!从今天开始,我们将进入 进阶阶段第三模块:并发与迭代(第 65-69 天)。
这是 Python 高级特性的核心领域。今天我们要学习的是整个迭代体系的基石——迭代器协议(Iterator Protocol)。理解它,你才能明白 for 循环的本质,并为明天学习生成器(Generator)和异步编程(Asyncio)打下坚实基础!
一、什么是迭代器协议?
1. 核心定义
迭代器协议 是 Python 中用于实现迭代对象的一套标准规则。任何对象只要实现了 __iter__() 和 __next__() 方法,就可以成为迭代器。
2. 可迭代对象 vs 迭代器
这是初学者最容易混淆的概念。
特性 | 可迭代对象 (Iterable) | 迭代器 (Iterator) |
|---|
定义 | 实现 __iter__ 方法 | 实现 __iter__ 和 __next__ |
用途 | 可以被迭代(如 for) | 实际执行迭代过程 |
示例 | list, tuple, str, dict
| iter(list), 文件对象
|
状态 | 无状态 | 有状态(记住当前位置) |
复用 | 可多次迭代 | 只能迭代一次 |
from collections.abc import Iterable, Iteratornumbers = [1, 2, 3]# 列表是可迭代对象print(isinstance(numbers, Iterable)) # Trueprint(isinstance(numbers, Iterator)) # False# 创建迭代器iterator = iter(numbers)print(isinstance(iterator, Iterator)) # True
💡 关键点:可迭代对象是"数据源",迭代器是"读取指针"。二、协议核心方法
1. __iter__() 方法
返回迭代器对象本身。这使得迭代器本身也是可迭代的。
class MyIterator: def __iter__(self): return self # 必须返回 self
2. __next__() 方法
返回下一个元素。如果没有更多元素,必须抛出 StopIteration 异常。
def __next__(self): if self.current >= self.end: raise StopIteration # 告诉循环结束了 value = self.current self.current += 1 return value
3. 内置函数支持
iter(obj): 调用 obj.__iter__()。next(obj): 调用 obj.__next__()。
iterator = iter([1, 2, 3])print(next(iterator)) # 1print(next(iterator)) # 2print(next(iterator, "默认值")) # 3 (带默认值避免异常)
三、for 循环的工作原理
for 循环是迭代器协议的语法糖。以下两段代码等价:
# 语法糖:for 循环for item in [1, 2, 3]: print(item)# 底层实现:while 循环iterator = iter([1, 2, 3])while True: try: item = next(iterator) print(item) except StopIteration: break
💡 理解:for 循环自动处理了 iter() 创建迭代器和 StopIteration 异常捕获。四、自定义迭代器(OOP 实战)
结合之前学过的 类与对象(参考 [File 67](67-实例方法与 self 的本质.md)),我们可以创建自己的迭代器。
1. 基础示例:计数器
class Counter: def __init__(self, start, end): self.current = start self.end = end def __iter__(self): return self def __next__(self): if self.current >= self.end: raise StopIteration value = self.current self.current += 1 return value# 使用counter = Counter(1, 5)for num in counter: print(num) # 1, 2, 3, 4
2. 进阶示例:反向迭代器
class Reverse: """反向迭代序列""" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def __next__(self): if self.index == 0: raise StopIteration self.index -= 1 return self.data[self.index]# 使用for char in Reverse("Python"): print(char) # n, o, h, t, y, P
3. 最佳实践:分离可迭代对象与迭代器
为了支持多次迭代,应该分离设计。
class NumberRange: """可迭代对象(可多次迭代)""" def __init__(self, start, end): self.start = start self.end = end def __iter__(self): return NumberRangeIterator(self.start, self.end)class NumberRangeIterator: """迭代器(一次性消费)""" def __init__(self, start, end): self.current = start self.end = end def __iter__(self): return self def __next__(self): if self.current >= self.end: raise StopIteration value = self.current self.current += 1 return value# 使用numbers = NumberRange(1, 4)print(list(numbers)) # [1, 2, 3]print(list(numbers)) # [1, 2, 3] (可以再次迭代)
五、内置迭代器工具
1. iter() 带哨兵值
可以创建一个迭代器,直到遇到特定值停止。
import randomdef roll_dice(): return random.randint(1, 6)# 一直掷骰子直到掷出 6for roll in iter(roll_dice, 6): print(f"掷出:{roll}")
2. 文件对象是迭代器
文件对象天然支持迭代器协议,逐行读取。
with open("data.txt", "r", encoding="utf-8") as f: for line in f: # 等价于 next(f) print(line.strip())
六、类型提示支持(结合进阶模块)
from collections.abc import Iterator, Iterabledef process_data(data: Iterable[int]) -> Iterator[int]: """处理可迭代数据,返回迭代器""" return (x * 2 for x in data)def consume(iterator: Iterator[str]) -> None: """消费迭代器""" for item in iterator: print(item)
七、常见误区与注意事项
1. 迭代器只能使用一次
迭代器是"一次性消耗品",用完即废。
iterator = iter([1, 2, 3])print(list(iterator)) # [1, 2, 3]print(list(iterator)) # [] (已耗尽)
2. 忘记返回 self
__iter__ 必须返回迭代器对象本身(通常是 self)。
# ❌ 错误def __iter__(self): pass # 返回 None# ✅ 正确def __iter__(self): return self
3. 忘记抛出 StopIteration
如果不抛出,循环将永远不会停止(无限循环)。
# ❌ 错误def __next__(self): return self.current # 没有终止条件# ✅ 正确def __next__(self): if self.current >= self.end: raise StopIteration return self.current
4. 无法随机访问
迭代器只能顺序访问,不支持索引。
iterator = iter([1, 2, 3])
# print(iterator[1]) # ❌ TypeError
八、总结
知识点 | 说明 |
|---|
Iterable | 实现 __iter__,可多次迭代(如 list) |
Iterator | 实现 __iter__ + __next__,一次性消费 |
__iter__
| 返回迭代器本身 |
__next__
| 返回下一个值,结束抛 StopIteration |
for 原理
| 自动调用 iter() 和 next() 捕获异常 |
类型提示 | Iterable[T], Iterator[T]
|
最佳实践 | 大数据用迭代器,需随机访问用列表 |
核心要点
- 迭代器协议是 Python 迭代的基石,
for 循环基于此实现。 - 迭代器是一次性的,耗尽后需重新创建。
- 自定义迭代器需实现两个方法,并注意终止条件。
- 分离可迭代对象与迭代器 可支持多次迭代。
- 文件对象天然支持迭代,逐行读取最省内存。
📌 明日预告:生成器函数与 yield 关键字
明天我们将进入 并发与迭代模块第二天!
- 主题:生成器函数与
yield 关键字 - 核心问题:
- 生成器与普通函数有什么区别?
yield 关键字的作用是什么?- 生成器表达式怎么写?
send(), throw(), close() 方法怎么用?- 生成器如何实现协程?
💡 提前思考:
- 如果不想写
__iter__ 和 __next__,有没有更简单的方法创建迭代器? yield 和 return 有什么区别?- 生成器为什么能节省内存?
掌握迭代器协议,是理解 Python 高效迭代的关键!明天学习更简洁的生成器!继续加油!🚀