为什么空列表的大小不是 0 字节?

Why isn't the size of an empty list 0 bytes?

今天我自己 运行 下面在 Python 2.7.13 中给出的代码,发现当它为空时列表大小不是 0 :

import sys
data = []
for k in range(n):
    a = len(data)
    b = sys.getsizeof(data)
    print('Length:{0:3d};Size in bytes:{1:4d}'.format(a,b))
    data.append(None)

我机器上的输出:

Length: 0; Size in bytes : 72
Length: 1; Size in bytes : 104
Length: 2; Size in bytes : 104
Length: 3; Size in bytes : 104
Length: 4; Size in bytes : 104
Length: 5; Size in bytes : 136
Length: 6; Size in bytes : 136
Length: 7; Size in bytes : 136
Length: 8; Size in bytes : 136
Length: 9; Size in bytes : 200
Length: 10; Size in bytes : 200
Length: 11; Size in bytes : 200
Length: 12; Size in bytes : 200
Length: 13; Size in bytes : 200
Length: 14; Size in bytes : 200
Length: 15; Size in bytes : 200
Length: 16; Size in bytes : 200
Length: 17; Size in bytes : 272
Length: 18; Size in bytes : 272
Length: 19; Size in bytes : 272

我想知道为什么会这样?

It seems that Python is reserving memory for something. What is that something??

因为列表的大小,如 return 从 sys.getsizeof 编辑的那样,不仅仅包括列表包含的元素。

Python 中的每个对象都由一个 C 结构表示;这个结构包含指向使列表成为列表的所有事物的指针(主要是它的方法)。调用 sys.getsizeof 时也会考虑到这一点。

您可以随时查看 GitHub 上 CPython 存储库主分支中的 implementation of list.__sizeof__:

static PyObject *
list___sizeof___impl(PyListObject *self)
{
    Py_ssize_t res;

    res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * sizeof(void*);
    return PyLong_FromSsize_t(res);
}

(删除不相关的 arg clinic 输出。)

sizeoffunction for 2.x做同样的事情。

return值res还包括列表对象类型的大小_PyObject_SIZE(Py_Type(self))

由于Python中的一切都是对象,这种行为随处可见,e.x,整数0

>>> getsizeof(0)
24

虽然您通常不会想到这一点,但当您意识到 Python 中的所有内容都具有 "additional baggage" 允许我们认为理所当然的行为时,这就非常有意义了。

Python 在 C 中实现,因此将在 C 结构中存储数据。

记住所有的东西都是'objects' - 对象必须有类型和对象大小,即使它们不存储任何东西.

下面是 PyObject_VAR_HEAD and PyListObject C 数据类型。

#define PyObject_VAR_HEAD               \
    PyObject_HEAD                       \
    Py_ssize_t ob_size; /* Number of items in variable part */

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size
     *     ob_item == NULL implies ob_size == allocated == 0
     * list.sort() temporarily sets allocated to -1 to detect mutations.
     *
     * Items must normally not be NULL, except during construction when
     * the list is not yet visible outside the function that builds it.
     */
    Py_ssize_t allocated;
} PyListObject;

请记住,sys.getsizeof() 将 return 底层内存使用情况,而不是您真正需要考虑或担心的事情 Python:

Return the size of an object in bytes.

Only the memory consumption directly attributed to the object is accounted for, not the memory consumption of objects it refers to.

此外,如您的测试所示,正在进行大量预分配。在 每次 调用 append().

时,新内存与 list 无关