在 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 的函数及惰性序列。