Python列表(元组)每个元素占多少字节?

18 投票
5 回答
16754 浏览
提问于 2025-04-11 09:31

比如,存储一百万个32位整数需要多少内存呢?

alist = range(1000000) # or list(range(1000000)) in Python 3.0

5 个回答

6

关于“元组”的部分

在CPython的一个典型构建配置中,PyTuple的声明大致是这样的:

struct PyTuple {
  size_t refcount; // tuple's reference count
  typeobject *type; // tuple type object
  size_t n_items; // number of items in tuple
  PyObject *items[1]; // contains space for n_items elements
};

PyTuple实例的大小在构造时是固定的,之后不能再改变。PyTuple占用的字节数可以通过以下公式计算:

sizeof(size_t) x 2 + sizeof(void*) x (n_items + 1).

这个公式给出的只是元组的表面大小。要得到完整的大小,还需要加上由PyTuple::items[]数组所指向的对象图所占用的总字节数。

值得注意的是,元组的构造过程确保只会创建一个空元组的实例(也叫单例模式)。

参考资料: Python.h, object.h, tupleobject.h, tupleobject.c

26

“这要看情况。” Python 在处理列表时,会以一种方式分配空间,以便在往列表中添加元素时,能保持大致恒定的时间效率。

具体来说,当前的实现方式是... 列表总是为一个2的幂次方数量的元素预留空间。所以,当你使用 range(1000000) 时,实际上会分配一个足够容纳 2^20 个元素(大约 104.5 万)的列表。

这只是存储列表结构本身所需的空间(这个结构是一个指向每个元素的 Python 对象的指针数组)。在32位系统中,每个元素需要4个字节,而在64位系统中,每个元素需要8个字节。

此外,你还需要空间来存储实际的元素。这部分的需求差别很大。对于小整数(目前是从-5到256),不需要额外的空间,但对于更大的数字,Python 会为每个整数分配一个新的对象,这样会占用10到100个字节,并且容易导致内存碎片。

总的来说:事情比较复杂,而且 Python 列表不适合存储大型的同类数据结构。如果你需要这样做,可以使用 array 模块,或者如果需要进行向量化运算,可以使用 NumPy。

另外,元组与列表不同,它们并不是为了逐渐添加元素而设计的。我不知道分配器是怎么工作的,但别想用它来处理大型数据结构 :-)

15

有用的链接:

如何获取Python对象的内存大小/使用情况

Python对象的内存大小是多少?

如果你把数据放入字典中,如何计算数据的大小?

不过这些链接并没有给出明确的答案。可以尝试以下方法:

  1. 使用操作系统工具,测量Python解释器在有/没有列表时消耗的内存。

  2. 使用一个第三方扩展模块,这个模块可以定义某种方式来获取PyObject的大小。

更新:

食谱546530:Python对象的大小(修订版)

import asizeof

N = 1000000
print asizeof.asizeof(range(N)) / N
# -> 20 (python 2.5, WinXP, 32-bit Linux)
# -> 33 (64-bit Linux)

撰写回答