跳到主要内容

什么是 Python 的生成器?

定义​

生成器(Generator)是一种惰性计算的迭代器,按需逐个产出值,而不是一次性将所有值存入内存。

Python 中有两种创建生成器的方式:

  1. 生成器函数:包含 yield 关键字的函数
  2. 生成器表达式:类似列表推导式,但用圆括号 ()

生成器函数​

def count_up(n):
i = 0
while i < n:
yield i # 暂停并产出值,下次调用从此处继续
i += 1

gen = count_up(3)
print(next(gen)) # 0
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # StopIteration 异常

每次调用 next() 时,函数从上次 yield 暂停的地方继续执行,直到下一个 yield 或函数结束。

生成器表达式​

# 列表推导式 —— 立即生成所有值,存入内存
squares_list = [x**2 for x in range(10)]

# 生成器表达式 —— 惰性计算,按需产出
squares_gen = (x**2 for x in range(10))

print(next(squares_gen)) # 0
print(next(squares_gen)) # 1

yield vs return​

returnyield
函数类型普通函数生成器函数
执行方式一次执行完毕每次 next() 执行一步
返回值单个值,函数终止逐个产出值,函数暂停
状态保留不保留保留局部变量和执行位置

内存对比​

import sys

# 列表:一次性分配所有内存
lst = [x for x in range(1_000_000)]
print(sys.getsizeof(lst)) # ~8 MB

# 生成器:固定极小内存
gen = (x for x in range(1_000_000))
print(sys.getsizeof(gen)) # ~112 字节

yield from —— 委托子生成器​

def flatten(nested):
for item in nested:
if isinstance(item, list):
yield from flatten(item) # 委托给子生成器
else:
yield item

print(list(flatten([1, [2, [3, 4]], 5])))
# [1, 2, 3, 4, 5]

典型应用场景​

1. 处理大文件​

def read_large_file(path):
with open(path) as f:
for line in f:
yield line.strip()

for line in read_large_file("huge.log"):
process(line) # 每次只有一行在内存中

2. 无限序列​

def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b

fib = fibonacci()
print([next(fib) for _ in range(8)])
# [0, 1, 1, 2, 3, 5, 8, 13]

3. 数据管道​

def read_data():
yield from range(10)

def filter_even(data):
for x in data:
if x % 2 == 0:
yield x

def square(data):
for x in data:
yield x ** 2

pipeline = square(filter_even(read_data()))
print(list(pipeline)) # [0, 4, 16, 36, 64]

生成器的状态​

生成器有四种状态(可用 inspect.getgeneratorstate() 查看):

状态含义
GEN_CREATED已创建,未开始执行
GEN_RUNNING正在执行
GEN_SUSPENDED在 yield 处暂停
GEN_CLOSED执行完毕或被关闭

总结​

  • 生成器的核心是 yield 暂停 + 恢复执行
  • 相比列表,生成器节省内存,适合大数据流、无限序列、数据管道
  • yield from 可以优雅地委托子生成器,简化递归迭代
  • 本质上,生成器是实现了迭代器协议(__iter__ + __next__)的对象