Python 生成器表达式
生成器表达式是创建轻量级迭代器的简洁语法,类似列表推导式但使用圆括号。
基本语法
Python
# 列表推导式:立即生成全部元素
lst = [x * 2 for x in range(5)]
print(lst) # [0, 2, 4, 6, 8]
# 生成器表达式:惰性生成
gen = (x * 2 for x in range(5))
print(gen) # <generator object>
print(list(gen)) # [0, 2, 4, 6, 8]
与列表推导式对比
Python
import sys
# 列表:预分配内存
lst = [x for x in range(10000)]
print(sys.getsizeof(lst)) # 约 87624 bytes
# 生成器:几乎不占内存
gen = (x for x in range(10000))
print(sys.getsizeof(gen)) # 约 112 bytes
| 特性 | 列表推导式 | 生成器表达式 |
|---|---|---|
| 括号 | [] | () |
| 内存 | 立即占用 | 惰性生成 |
| 可迭代 | 多次 | 一次 |
| 索引访问 | 支持 | 不支持 |
| 适用场景 | 需要全部元素 | 流式处理 |
惰性求值
Python
# 列表推导式:立即执行所有计算
results = [x ** 2 for x in range(1000000)] # 立即计算全部
# 生成器表达式:按需计算
results_gen = (x ** 2 for x in range(1000000))
print(next(results_gen)) # 0(只计算第一个)
带条件过滤
Python
# 过滤偶数
evens = (x for x in range(20) if x % 2 == 0)
print(list(evens)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# 多条件
filtered = (x for x in range(20) if x > 5 and x % 2 == 0)
print(list(filtered)) # [6, 8, 10, 12, 14, 16, 18]
嵌套循环
Python
# 生成坐标对
coords = ((x, y) for x in range(3) for y in range(3))
print(list(coords))
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
# 嵌套条件
pairs = ((x, y) for x in range(5) if x > 2 for y in range(5) if y < x)
print(list(pairs))
# [(3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3)]
函数参数中的生成器表达式
在函数参数中,圆括号可省略:
Python
# 等价写法
sum((x for x in range(10))) # 45
sum(x for x in range(10)) # 45(省略括号)
max(x ** 2 for x in range(10)) # 81
min(x for x in [-1, 0, 1]) # -1
# 生成器作为参数,避免创建中间列表
total = sum(x * 2 for x in range(1000000)) # 高效
# 而非 total = sum([x * 2 for x in range(1000000)]) # 低效
链式操作
生成器表达式可与其他迭代工具组合:
Python
from itertools import islice, takewhile
# 切片
gen = (x ** 2 for x in range(100))
print(list(islice(gen, 5))) # [0, 1, 4, 9, 16]
# 条件取值
gen = (x for x in range(20))
result = list(takewhile(lambda x: x < 5, gen))
print(result) # [0, 1, 2, 3, 4]
# 多阶段管道
data = range(100)
stage1 = (x * 2 for x in data) # 加倍
stage2 = (x for x in stage1 if x > 50) # 过滤
stage3 = (x / 10 for x in stage2) # 除以10
print(list(stage3)) # [5.2, 5.4, 5.6, ..., 19.8]
实际应用
处理大文件
Python
# 读取文件行(惰性)
lines = (line.strip() for line in open('large.txt'))
# 过滤空行
non_empty = (line for line in lines if line)
# 提取数据
data = (parse_line(line) for line in non_empty)
# 流式处理,不一次性加载全部内容
for item in data:
process(item)
数据转换管道
Python
# 多步转换
raw_data = [1, -2, 3, -4, 5]
# 过滤 → 转换 → 格式化
pipeline = (
f"value: {x}"
for x in (abs(x) for x in raw_data)
if x > 2
)
print(list(pipeline)) # ['value: 3', 'value: 4', 'value: 5']
聚合计算
Python
# 计算平均值(不创建中间列表)
data = range(1000000)
avg = sum(x for x in data) / len(data)
# 条件聚合
total = sum(x for x in range(100) if x % 3 == 0)
print(total) # 1683
注意事项
一次性消耗
Python
gen = (x for x in range(5))
print(list(gen)) # [0, 1, 2, 3, 4]
print(list(gen)) # [](已耗尽)
不支持索引
Python
gen = (x for x in range(5))
# gen[0] # TypeError: 不支持索引
# 必须转换为列表才能索引
lst = list(gen)
print(lst[0]) # 0
不能切片
Python
gen = (x for x in range(10))
# gen[2:5] # TypeError
# 使用 islice
from itertools import islice
print(list(islice(gen, 2, 5))) # [2, 3, 4]
转换为其他类型
Python
gen = (x for x in range(5))
# 转列表
lst = list(gen) # [0, 1, 2, 3, 4]
# 转元组
gen = (x for x in range(5))
tup = tuple(gen) # (0, 1, 2, 3, 4)
# 转集合
gen = (x % 3 for x in range(10))
s = set(gen) # {0, 1, 2}
与生成器函数等价
Python
# 生成器表达式
gen_expr = (x ** 2 for x in range(5))
# 等价的生成器函数
def gen_func():
for x in range(5):
yield x ** 2
# 两者效果相同
print(list(gen_expr)) # [0, 1, 4, 9, 16]
print(list(gen_func())) # [0, 1, 4, 9, 16]
要点总结
| 特性 | 说明 |
|---|---|
| 语法 | (expression for item in iterable if condition) |
| 括号 | 函数参数中可省略 |
| 惰性 | 按需生成,节省内存 |
| 一次性 | 只能迭代一次 |
| 组合 | 可与 itertools 链式组合 |
生成器表达式适合简单迭代场景,复杂逻辑优先使用生成器函数。
D:\git2\jwdev\articles\PYTHON\进阶\迭代器与生成器\生成器表达式.md
📝 发现内容有误?点击此处直接编辑