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

时间:2017-03-30 14:04:03

标签: python python-2.7 list python-3.x python-internals

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

import sys as s
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

我想知道为什么会这样?

  

似乎Python正在为某些东西保留内存。   那是什么东西?

2 个答案:

答案 0 :(得分:4)

因为从sys.getsizeof返回的列表大小不仅包含列表包含的元素。

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

您可以随时查看GitHub上CPython存储库主分支中的ProcessCmdKey

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诊所输出。)

sizeof implementation of list.__sizeof__做同样的事情。

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

由于Python中的所有内容都是对象,因此可以在任何地方观察到此行为,e.x,整数0

>>> getsizeof(0)
24

虽然你通常不会期望这一点,但当你意识到Python中的所有东西都有“额外的包袱”允许我们认为理所当然的行为时,它就非常有意义。

答案 1 :(得分:1)

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

请记住,所有事物都是'对象' - 对象必须具有类型和对象大小,即使他们不存储任何

以下是PyObject_VAR_HEADPyListObject 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()将返回基础内存使用情况,而不是您真正需要考虑或担心Python的内容:

  

以字节为单位返回对象的大小。

     

只考虑直接归因于对象的内存消耗,而不是它所引用的对象的内存消耗。

此外,正如您的测试所示,有一定数量的预分配正在进行中。新内存与每次 list上的append()无关。