为何Python列表推导式无法像[1]*i一样预分配内存?
列表推导式与
[1]*i的内存分配差异解析 问题背景
执行以下代码时:
import sys for i in range(30): print(sys.getsizeof([1 for _ in range(i)]))
输出结果为2的幂;而执行以下代码时:
for i in range(30): print(sys.getsizeof([1]*i))
输出结果为线性增长的较小值。
疑问:第一个示例中Python似乎在列表推导式循环中反复创建并扩容数组,而第二个示例能一次性分配正确尺寸的数组。为何前者无法识别range(i)会生成i个元素从而进行优化?
核心原因
[1]*i的专属优化:这种语法是Python针对「固定元素重复生成列表」场景做的特殊优化。解释器执行时明确知道要创建的列表长度是i,可以直接分配刚好容纳i个元素的内存空间(加上列表对象本身的固定开销),因此内存占用随元素数量线性增长,和实际元素数精准匹配。列表推导式的通用适配逻辑:列表推导式是通用的迭代生成工具,需要兼容所有类型的迭代器——不仅是
range这种有明确长度的迭代器,还包括没有__len__方法、无法提前获知元素数量的自定义迭代器。为了覆盖所有场景,它采用动态扩容策略:初始分配小容量内存,当元素数量超过当前容量时,按2的幂次扩容(比如4→8→16…),这就导致输出的内存大小呈现2的幂次特征。
哪怕推导式里用的是range(i)这种长度明确的迭代器,Python解释器也不会为这一种特殊场景修改通用逻辑——毕竟要保证所有迭代场景下的一致性,额外做类型判断反而会增加解释器的复杂度,得不偿失。
内容的提问来源于stack exchange,提问作者lezebulon
相关产品推荐
相关产品推荐

