什么是 Python 的生成器?
定义
生成器(Generator)是一种惰性计算的迭代器,按需逐个产出值,而不是一次性将所有值存入内存。
Python 中有两种创建生成器的方式:
- 生成器函数:包含
yield关键字的函数 - 生成器表达式:类似列表推导式,但用圆括号
()
生成器函数
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
return | yield | |
|---|---|---|
| 函数类型 | 普通函数 | 生成器函数 |
| 执行方式 | 一次执行完毕 | 每次 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__)的对象