为什么拥有相同数据的列表大小不同?

11

假设我用两种方法创建Python lists

第一种情况下,我使用简单的赋值:

my_list = []
print(my_list, '->', my_list.__sizeof__())
my_list = [1]
print(my_list, '->', my_list.__sizeof__())
my_list = [1, 1]
print(my_list, '->', my_list.__sizeof__())
在第二种情况下,我使用列表上的append()方法:
my_list = []
print(my_list, '->', my_list.__sizeof__())
my_list.append(1)
print(my_list, '->', my_list.__sizeof__())
my_list.append(1)
print(my_list, '->', my_list.__sizeof__())

但我得到了意料之外(对我来说)的输出:

=== WITH ASSIGNMENT ===
([], '->', 40)
([1], '->', 48)
([1, 1], '->', 56)
=== WITH APPEND ===
([], '->', 40)
([1], '->', 72)
([1, 1], '->', 72)

Python内存管理在内部会发生什么? 为什么“相同”的列表大小不同?


3
我猜原因是当你用Python字面值创建列表时,Python会分配需要的特定大小,而当你添加元素时,它会扩展超过所需空间,这是基于假设你不止一次添加元素。 - jonrsharpe
Python列表访问和调整大小的内部运行时间。 - anuragal
也相关的问题:list()使用比列表推导式更多的内存 - vishes_shell
1个回答

19
当您向列表中添加内容时,为了提高性能,内存会超额分配到列表中,以便多次添加不需要对列表进行相应的内存重新分配,否则在重复添加的情况下会降低整体性能。CPython源代码清楚地描述了这种行为在一个comment中:
/* This over-allocates proportional to the list size, making room
 * for additional growth.  The over-allocation is mild, but is
 * enough to give linear-time amortized behavior over a long
 * sequence of appends() in the presence of a poorly-performing
 * system realloc().
 * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
 * Note: new_allocated won't overflow because the largest possible value
 *       is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
 */

在另一种情况下,列表是由一个字面量构建的,列表的大小反映了容器本身的大小和对每个包含对象的引用。
确切的分配行为可能会因其他Python实现(请参见JythonPyPy的list.append实现)而有所不同,并且过度分配不能保证存在。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接