Python 迭代器(Iterator)
迭代器是 Python 中支持惰性遍历的核心机制。简单来说,它是一个可以记住遍历位置的对象,每次调用 next() 就返回下一个值,直到没有更多元素时抛出 StopIteration 异常。
1. 迭代器协议
一个对象要成为迭代器,必须实现两个方法:
__iter__():返回迭代器对象自身(通常就是self)。__next__():返回下一个可用元素;如果没有元素了,必须抛出StopIteration。
class MyIterator:
def __init__(self, limit):
self.limit = limit
self.current = 0
def __iter__(self):
return self # 迭代器返回自身
def __next__(self):
if self.current < self.limit:
value = self.current
self.current += 1
return value
else:
raise StopIteration
it = MyIterator(3)
print(next(it)) # 0
print(next(it)) # 1
print(next(it)) # 2
# print(next(it)) # StopIteration
2. 可迭代对象 vs 迭代器
| 概念 | 特点 | 示例 |
|---|---|---|
| 可迭代对象 (Iterable) | 实现了 __iter__() 方法,能返回一个迭代器 | list, str, tuple, dict, set, 文件对象 |
| 迭代器 (Iterator) | 实现了 __iter__() 和 __next__() 方法 | generator 对象, enumerate 对象, zip 对象, 自定义迭代器 |
关系:可迭代对象不一定是迭代器,但迭代器一定是可迭代对象(因为它有 __iter__)。
lst = [1, 2, 3]
print(hasattr(lst, '__iter__')) # True → 可迭代
print(hasattr(lst, '__next__')) # False → 不是迭代器
it = iter(lst) # 从列表获取迭代器
print(hasattr(it, '__iter__')) # True
print(hasattr(it, '__next__')) # True → 是迭代器
3. for 循环背后的迭代器
for x in iterable: 的本质是:
- 调用
iter(iterable)获取一个迭代器。 - 反复调用
next(迭代器)将返回值赋给x。 - 捕获
StopIteration并退出循环。
# 等价于
it = iter([1, 2, 3])
while True:
try:
x = next(it)
print(x)
except StopIteration:
break
4. 生成器:最方便的迭代器
生成器(使用 yield 的函数或生成器表达式)自动实现迭代器协议,不需要手动编写 __iter__ 和 __next__。
def gen(n):
for i in range(n):
yield i
g = gen(3)
print(next(g)) # 0
print(next(g)) # 1
print(next(g)) # 2
# print(next(g)) # StopIteration
生成器是迭代器的子类型,因此可以用于任何需要迭代器的地方。
5. 迭代器的特性
- 惰性求值:只在需要时计算下一个值,节省内存。
- 单向:只能向前,不能重置或后退。
- 一次性:遍历完毕后,无法再次使用(除非重新创建)。
- 内置支持:
next()、iter()函数,以及for、list()、sum()等都会自动使用迭代器。
6. 常见内置迭代器
enumerate(iterable)→ 返回 (索引, 元素) 的迭代器。zip(iter1, iter2)→ 并行聚合多个迭代器的迭代器。reversed(sequence)→ 反向遍历的迭代器。map(func, iterable)→ 应用函数结果的迭代器。filter(pred, iterable)→ 筛选元素的迭代器。
7. 手动控制迭代器
使用 next() 手动推进:
fruits = ['apple', 'banana', 'cherry']
it = iter(fruits)
print(next(it)) # apple
print(next(it)) # banana
print(list(it)) # ['cherry'] 注意:剩余元素被消费
8. 总结
| 你需要知道的关键点 |
|---|
迭代器是实现了 __next__() 和 __iter__() 的对象 |
可迭代对象通过 iter() 产生迭代器 |
for 循环底层完全依赖迭代器 |
| 生成器是最简单的迭代器创建方式 |
| 迭代器是惰性、单向、一次性的 |
理解迭代器后,你会更清楚 Python 如何高效处理大数据流、文件读取、无限序列等场景。
是的,你的理解基本正确。for 循环在执行时,会按照迭代器协议自动完成以下步骤:
-
检查目标是否可迭代:通过调用内置函数
iter(目标),这要求目标对象实现了__iter__()方法。如果没实现,iter()会抛出TypeError: '...' object is not iterable。 -
获取迭代器:
iter(目标)返回一个迭代器对象(这个对象必须实现了__next__()方法)。 -
反复调用
next():for循环内部不断调用next(迭代器),每次拿到返回值赋给循环变量,直到next()抛出StopIteration异常,循环结束。
所以,for 循环的完整判断逻辑是:
- 目标是否可迭代 → 即是否有
__iter__方法(或__getitem__作为后备,但现代 Python 主要依赖__iter__)。 - 迭代器是否有
__next__→ 否则next()调用会失败。
你提到的“对应的迭代器中有 next 函数”正是第 3 步能正常工作的前提。
验证示例
# 一个没有 __iter__ 的类
class NotIterable:
pass
obj = NotIterable()
for x in obj: # TypeError: 'NotIterable' object is not iterable
pass
# 一个有 __iter__ 但返回的对象没有 __next__
class BadIterable:
def __iter__(self):
return 123 # 返回的不是迭代器(没有 __next__)
obj2 = BadIterable()
for x in obj2: # TypeError: iter() returned non-iterator of type 'int'
pass
因此,for 循环隐式但严格地依赖这两个方法的存在。你的表述“先判断目标是否是可迭代对象,且目标中有 iter 函数,且对应的迭代器中有 next 函数”基本准确,只是更精确地说:for 会先调用 iter() 来触发检查,然后要求返回的对象支持 next()。