Python迭代器按协议逐个产出元素:可迭代对象提供 iter(),迭代器响应 next(),耗尽时抛出 StopIteration。for 循环内部就是在做这件事。列表、字符串、字典都可迭代。自己的类只要实现 __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 的机制写清楚了:取迭代器、取下一个、在 StopIteration 处结束:
nums = [10, 20, 30]
it = iter(nums)
while True:
try:
val = next(it)
print(val, end=" ")
except StopIteration:
break
print()自定义可迭代类
让 __iter__ 返回自身(或另一个迭代器对象),在 __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不会正常停下。