讲解

for 循环背后是一套「迭代协议」:可迭代对象(iterable,如列表、字符串、字典)实现 iter 返回迭代器;迭代器(iterator)实现 next,每次调用给出下一个元素,耗尽时抛 StopIteration——for 循环正是靠捕获这个异常知道该停了。iter() 和 next() 内置函数是这套协议的手动入口。迭代器是「一次性」的:耗尽后再 next 永远是 StopIteration,想再遍历一遍要重新 iter()。

生成器(generator)是创建迭代器的简便方式:函数里出现 yield 关键字,它就不再是普通函数——调用它不执行函数体,而是返回一个生成器对象;每次 next 时执行到下一个 yield 暂停并交出值,下次从暂停处继续,局部变量全部保留。这种「惰性求值」意味着数据是一个一个算出来的:处理 10 GB 的日志文件、生成无穷数列,内存占用都是常量。range、map、zip、enumerate 全是惰性迭代器,这是 Python 3 的默认风格。

生成器的两个进阶形态:生成器表达式 (x * x for x in nums)——把列表推导式的方括号换成圆括号,得到惰性版本,sum(x*x for x in nums) 甚至不需要括号;yield from 用于在生成器里委托另一个生成器,def chain(a, b): yield from a; yield from b。消费惰性数据的工具链在 itertools 模块里:islice 切片无限序列、count/cycle 造无限流、chain 拼接。记住惰性是把双刃剑:省内存,但只能消费一次,且错误会推迟到消费时才暴露。

示例

# 手动体验迭代协议
nums = [10, 20, 30]
it = iter(nums)
print('手动 next:', next(it), next(it), next(it))
try:
    next(it)
except StopIteration:
    print('耗尽:抛 StopIteration,for 循环靠它知道停')

# 迭代器是一次性的
print('再 iter 才是新的:', list(iter(nums)), ',旧的:', list(it))

# yield:函数变生成器
def countdown(n):
    print('(生成器开始执行)')
    while n > 0:
        yield n
        n -= 1


gen = countdown(3)
print('调用时不执行:', gen)
print('逐个取出:', list(gen))

# 惰性:斐波那契无穷流,取前 10 个
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b


from itertools import islice

print('斐波那契前 10 项:', list(islice(fibonacci(), 10)))

# 生成器表达式:惰性的推导式
squares = (x * x for x in range(1000000))  # 不占内存
print('类型:', type(squares).__name__)
print('惰性求和:', sum(x * x for x in range(10)))

# yield from:委托子生成器
def flatten(nested):
    for sub in nested:
        yield from sub


print('摊平:', list(flatten([[1, 2], [3], [4, 5]])))

常见坑

  • 把迭代器当列表反复遍历:list(it) 消费完,再 list(it) 就是空的。需要多次使用就一开始就 materialize 成列表。
  • 以为生成器函数调用即执行:gen = f() 只是拿到生成器,函数体一行都没跑,连参数校验都推迟到第一次 next。调试时别被「没报错」迷惑。
  • 在生成器里 return 值拿不到:生成器 return x 的值会藏在 StopIteration 的 value 里,for 循环拿不到。想产出数据就用 yield。
  • 对 range/map 结果取下标或看长度:map 对象不支持 len() 和 [],要么 list() 转换,要么改用推导式。

小结

迭代协议 = iter + next + StopIteration;yield 让函数成为惰性生成器,省内存但一次性;生成器表达式和 itertools 是消费利器。下一章看 Python 最上镜的语法:推导式。