Python 列表推导式与生成器对比

Python 列表推导式与生成器对比

一、两者解决的都是“批量转换”

处理一个序列、按规则生成另一个序列时,列表推导式和生成器是 Python 最常用的两种写法。它们语法相近,但内存模型完全不同:一个一次性把结果装进列表,一个按需逐个产出。

二、列表推导式

方括号 [] 包裹,立刻计算并返回完整列表:

# 把 0~9 的偶数平方放进列表
result = [x * x for x in range(10) if x % 2 == 0]
print(result)  # [0, 4, 16, 36, 64]

特点:所有结果同时占内存,可以反复索引、len()、切片;适合数据量小、需要多次访问的场景。

三、生成器表达式

圆括号 () 包裹,返回一个生成器对象,不立即计算:

g = (x * x for x in range(10) if x % 2 == 0)
print(g)  # <generator object ...>
print(next(g))  # 0
print(list(g))  # [4, 16, 36, 64]

每调用一次 next 才算下一个值,用完即弃,内存恒定,适合大数据流、文件逐行处理。

四、生成器函数 yield

用 yield 定义的函数也是生成器:

def squares(n):
    for x in range(n):
        yield x * x

for v in squares(5):
    print(v)  # 0 1 4 9 16

函数执行到 yield 暂停,返回值并记住现场,下次从暂停处继续,不会一次性构造列表。

五、内存与性能对比

import sys
a = [x for x in range(1_000_000)]
b = (x for x in range(1_000_000))
print(sys.getsizeof(a))  # 占用很大(约 8MB 级别,随数据增长)
print(sys.getsizeof(b))  # 固定很小(生成器对象本身)
  • 列表:O(n) 内存,可随机访问,计算一次性完成;
  • 生成器:O(1) 内存,只能顺序迭代,且只能遍历一次;
  • 生成器不能 len()、不能切片,遍历完就空了。

六、怎么选

  1. 结果要复用、要排序、要索引、数据量小 → 列表推导式;
  2. 处理超大文件、无限流、管道式计算 → 生成器;
  3. 直接传给 sum、max、join 这类消费函数时,用生成器更省内存:
    total = sum(x * x for x in range(1_000_000))

七、常见误区

  1. 以为生成器能反复遍历,第一次 for 循环后再取就是空;
  2. 大数据还套列表推导式,直接内存爆满;
  3. 把生成器当列表用 len(),报 TypeError;
  4. 嵌套推导式过度复杂,可读性下降,不如拆成普通循环;
  5. 生成器内部异常会在 next 时才暴露,调试时机靠后。

八、总结

列表推导式用 [] 一次性产出完整列表,适合小数据与重复访问;生成器表达式用 () 或 yield 按需产出,内存恒定但只能顺序消费一次。选择依据是数据规模和是否需要复用:小而多用列表,大而流式用生成器,传给归约函数优先用生成器省内存。


emer 发布于  2026-11-15 07:20 
'); })();