列表推导式和生成器表达式有什么区别?
这个问题看起来基础,但实际用起来挺看细节的。我按内存模型、执行时机、使用场景这条线来讲,中间用个简图对比。
🧱 最核心的区别:生成数据的姿势完全不同¶
列表推导式:一运行就老老实实把所有元素算出来,塞进一个新列表,然后返回给你。整个过程是急迫的、一次性的。
生成器表达式:运行时根本不算任何值,只是返回一个生成器对象。这个对象肚子里装着“怎么产生元素”的规则,你每次用 next() 或迭代它,它才现算一个值给你。是惰性的、按需的。
用图表示就是:

💾 内存占用上的本质差异¶
这个区别在数据量大的时候会被放大: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 字节左右
列表推导式直接吞掉百万个整数对象和列表结构的内存。生成器表达式才占几百字节,因为它根本没存那些值。
所以一个很粗暴的结论:当你只需要遍历一次,就别让几百万个数字同时在内存里扎堆,用生成器表达式。
⏱️ 执行时机和迭代行为¶
-
列表推导式:赋值那一刻就全算完了,之后你对结果列表做什么操作都很快(随机访问、切片、多次迭代)。
-
生成器表达式:只有在被迭代时才一步步走,而且只能走一遍,走完就空了。不能往回倒,不能求长度,不能切片。
比如:
而列表可以反复迭代、随机取 lst[3]。这就是“一次性”和“持久化”的选择。