在 Python 中,迭代器按协议逐个产生元素:可迭代对象提供 iter(),迭代器响应 next(),元素耗尽时抛出 StopIteration。for 循环在内部即反复调用 next 直至捕获该异常。列表、字符串、字典等均为可迭代对象;自定义类实现 __iter__ 与 __next__ 后亦可被 for 遍历。本节说明协议含义及手写迭代器的写法。
手动驱动迭代器
iter(序列) 得到迭代器,再反复调用 next。元素取尽后继续 next 将引发 StopIteration:
nums = [1, 2, 3]
it = iter(nums)
print(next(it))
print(next(it))
print(next(it))
# print(next(it)) # StopIteration
可迭代对象与迭代器
- 可迭代对象:可交给
iter()并得到迭代器的对象,如列表、元组、字符串、字典、集合。 - 迭代器:实现
__next__(通常亦实现__iter__)的对象,负责产出下一个元素。
print(iter([1, 2]))
print(iter("hi"))
print(iter({"a": 1}))对字典调用 iter 时,默认遍历键。须遍历值或键值对时,使用 iter(d.values()) 或 iter(d.items())。
for 循环的等价过程
下列 while 展示了 for 的内部机制:获取迭代器、调用 next、在 StopIteration 处结束:
nums = [10, 20, 30]
it = iter(nums)
while True:
try:
val = next(it)
print(val, end=" ")
except StopIteration:
break
print()自定义可迭代类
__iter__ 返回迭代器对象(常为 self);__next__ 推进状态并在结束时抛出 StopIteration。下列倒计时类可被 for 使用:
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
for x in Countdown(3):
print(x, end=" ")
print()惰性产生元素
迭代器不必预先构造全部元素。range 在跨度很大时仍仅在迭代时产出整数,适合直接交给 sum 等消费方:
r = range(10000000)
print(sum(r))
print(type(r))常见错误
- 迭代器通常只能完整遍历一次;再次遍历须重新
iter(...)或重新构造可迭代对象。 - 字典默认迭代键,勿误以为在迭代值。
- 自定义
__next__在结束时须抛出StopIteration,否则for无法正常终止。
本节说明了 Python 中迭代器协议及自定义可迭代类。下一节介绍生成器:含 yield 的函数及惰性序列。