本文目录导读:

Python 生成器(Generator)的典型用法主要体现在处理大数据流、惰性计算、无限序列和协程等场景,以下是几个经典的案例,从基础到进阶展示生成器的核心价值。
读取大文件(最经典)
避免一次性加载整个文件到内存。
def read_large_file(file_path):
"""逐行读取文件,每次只返回一行"""
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
yield line.strip()
# 使用示例:处理10GB的日志文件
for line in read_large_file('huge_log.txt'):
if 'ERROR' in line:
process_error(line) # 内存始终只占一行大小
斐波那契数列(无限序列)
生成器可以轻松表示无限序列,而不会耗尽内存。
def fibonacci():
"""生成无限的斐波那契数列"""
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# 只取前10个
fib = fibonacci()
first_10 = [next(fib) for _ in range(10)]
print(first_10) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# 或者用 itertools 切片
from itertools import islice
fib_slice = list(islice(fibonacci(), 5, 15)) # 第5到第14个
数据流式处理(管道模式)
将多个生成器串联起来形成处理管道。
def read_numbers(file_path):
"""从文件读取数字"""
with open(file_path) as f:
for line in f:
yield int(line.strip())
def filter_even(numbers):
"""过滤出偶数"""
for num in numbers:
if num % 2 == 0:
yield num
def square(numbers):
"""计算平方"""
for num in numbers:
yield num ** 2
# 组装管道:读取 -> 过滤 -> 平方
pipeline = square(filter_even(read_numbers('data.txt')))
for result in pipeline:
print(result) # 逐个处理,不生成中间列表
实现类似 range 的自定义序列
展示 yield 的控制流能力。
def my_range(start, stop=None, step=1):
"""模拟内置 range 函数,但更灵活"""
if stop is None:
start, stop = 0, start
if step == 0:
raise ValueError("step cannot be zero")
if step > 0:
while start < stop:
yield start
start += step
else:
while start > stop:
yield start
start += step
# 使用
for i in my_range(10, 0, -2):
print(i) # 10, 8, 6, 4, 2
协程与双向通信(yield 接收值)
展示了 yield 作为表达式接收外部值的用法。
def echo_processor():
"""处理并返回结果,同时接收外部输入"""
print("处理器启动...")
while True:
received = yield # 接收外部发送的值
print(f"收到: {received}")
# yield 也可以同时返回结果(需要先 send 启动)
# 这里用 yield 接收,不返回
# 使用
proc = echo_processor()
next(proc) # 启动到第一个 yield 处,输出 "处理器启动..."
proc.send("Hello") # 输出 "收到: Hello"
proc.send("World") # 输出 "收到: World"
# 更实用的例子:累加器
def accumulator():
total = 0
while True:
value = yield total # 返回当前总和,同时接收新值
total += value
acc = accumulator()
next(acc) # 启动
print(acc.send(10)) # 输出 10
print(acc.send(5)) # 输出 15
print(acc.send(3)) # 输出 18
生成器表达式(简洁写法)
与列表推导式类似,但返回生成器对象。
# 列表推导式:立即生成所有元素,占用内存
squares_list = [x**2 for x in range(1000000)] # 占用~8MB内存
# 生成器表达式:惰性计算,几乎不占内存
squares_gen = (x**2 for x in range(1000000)) # 生成器对象,内存很小
# 使用时才计算
for sq in squares_gen:
if sq > 100:
break
print(sq) # 只计算到第10个就停止了
# 实际应用:统计文件关键词
word_count = sum(1 for line in open('file.txt') if 'keyword' in line)
深度优先遍历(树结构)
生成器非常适合递归遍历树形结构。
class TreeNode:
def __init__(self, value, children=None):
self.value = value
self.children = children or []
def dfs(tree):
"""深度优先遍历生成器"""
yield tree.value
for child in tree.children:
yield from dfs(child) # yield from 简化递归生成
# 构建树
root = TreeNode(1, [
TreeNode(2, [TreeNode(4), TreeNode(5)]),
TreeNode(3, [TreeNode(6)])
])
# 遍历
print(list(dfs(root))) # [1, 2, 4, 5, 3, 6]
无限素数生成器
结合埃拉托色尼筛法,实现惰性素数序列。
def primes():
"""生成无限素数序列"""
yield 2
seen = {4: 2} # 合数: 最小质因子
n = 3
while True:
factor = seen.get(n)
if factor is None:
# n 是素数
yield n
seen[n * n] = n
else:
# n 是合数,更新下一个位置
next_val = n + factor
while next_val in seen:
next_val += factor
seen[next_val] = factor
del seen[n]
n += 2 # 只检查奇数
# 获取前20个素数
from itertools import islice
print(list(islice(primes(), 20)))
| 特性 | 列表/普通函数 | 生成器 |
|---|---|---|
| 内存占用 | 一次性加载所有 | 每次只处理一个元素 |
| 无限序列 | 不可能 | 天然支持 |
| 惰性计算 | 立即执行 | 按需计算 |
| 状态保存 | 需手动维护 | 自动保存执行状态 |
| 适用场景 | 数据量小、需要多次访问 | 大数据流、管道处理 |
选择生成器的黄金法则:如果你不需要同时访问所有元素,而只需要逐一处理,就应该考虑用生成器替换列表推导或普通函数。