跳转至

列表推导式和生成器表达式有什么区别?

这个问题看起来基础,但实际用起来挺看细节的。我按内存模型、执行时机、使用场景这条线来讲,中间用个简图对比。


🧱 最核心的区别:生成数据的姿势完全不同

列表推导式:一运行就老老实实把所有元素算出来,塞进一个新列表,然后返回给你。整个过程是急迫的、一次性的。

生成器表达式:运行时根本不算任何值,只是返回一个生成器对象。这个对象肚子里装着“怎么产生元素”的规则,你每次用 next() 或迭代它,它才现算一个值给你。是惰性的、按需的。

用图表示就是:

image.png

💾 内存占用上的本质差异

这个区别在数据量大的时候会被放大:2

import sys

lst = [i for i in range(1000000)]
gen = (i for i in range(1000000))

print(sys.getsizeof(lst))   # 大概 8MB+
print(sys.getsizeof(gen))   # 只有 200 字节左右

列表推导式直接吞掉百万个整数对象和列表结构的内存。生成器表达式才占几百字节,因为它根本没存那些值。

所以一个很粗暴的结论:当你只需要遍历一次,就别让几百万个数字同时在内存里扎堆,用生成器表达式。


⏱️ 执行时机和迭代行为

  • 列表推导式:赋值那一刻就全算完了,之后你对结果列表做什么操作都很快(随机访问、切片、多次迭代)。

  • 生成器表达式:只有在被迭代时才一步步走,而且只能走一遍,走完就空了。不能往回倒,不能求长度,不能切片。

比如:

gen = (x for x in range(5))
print(list(gen))   # [0,1,2,3,4]
print(list(gen))   # []  —— 已经耗尽了

而列表可以反复迭代、随机取 lst[3]。这就是“一次性”和“持久化”的选择。