python占多少空间_python - 为什么元组在内存中占用的空间少于列表?

我将深入研究CPython代码库,以便我们可以看到实际计算的大小。 在您的具体示例中,没有执行过度分配,因此我不会涉及到这一点。

我将在这里使用64位值。

Py_SIZEs的大小由以下函数Py_SIZE计算:

static PyObject *

list_sizeof(PyListObject *self)

{

Py_ssize_t res;

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

return PyInt_FromSsize_t(res);

}

这里Py_SIZE是抓取0的Py_SIZE(返回tp_itemsize)的宏,而tp_itemsize是从该类型抓取Py_SIZE的另一个宏。 tp_basicsize计算为sizeof(PyListObject),其中PyListObject是实例结构。

Py_SIZE结构有三个字段:

PyObject_VAR_HEAD # 24 bytes

PyObject **ob_item; # 8 bytes

Py_ssize_t allocated; # 8 bytes

这些评论(我修剪)解释它们是什么,按照上面的链接阅读它们。 Py_SIZE扩展为三个8字节字段(Py_SIZE,0和tp_itemsize),因此有tp_itemsize字节的贡献。

所以目前Py_SIZE是:

sizeof(PyListObject) + self->allocated * sizeof(void*)

要么:

40 + self->allocated * sizeof(void*)

如果列表实例具有已分配的元素。 第二部分计算他们的贡献。 Py_SIZE,顾名思义,保存已分配元素的数量。

没有任何元素,列表的大小计算为:

>>> [].__sizeof__()

40

即实例结构的大小。

Py_SIZE对象未定义0功能。 相反,他们使用Py_SIZE来计算它们的大小:

static PyObject *

object_sizeof(PyObject *self, PyObject *args)

{

Py_ssize_t res, isize;

res = 0;

isize = self->ob_type->tp_itemsize;

if (isize > 0)

res = Py_SIZE(self) * isize;

res += self->ob_type->tp_basicsize;

return PyInt_FromSsize_t(res);

}

对于Py_SIZEs,这获取0,如果对象具有非零tp_itemsize(意味着它具有可变长度实例),则它将元组中的项目数(通过Py_SIZE获得)与tp_itemsize相乘。

Py_SIZE再次使用0,其中Py_SIZE结构包含:

PyObject_VAR_HEAD # 24 bytes

PyObject *ob_item[1]; # 8 bytes

因此,没有任何元素(即Py_SIZE返回0),空元组的大小等于list:

>>> ().__sizeof__()

24

是吧? 好吧,这是一个奇怪的我没有找到解释,list的tp_basicsizes实际计算如下:

sizeof(PyTupleObject) - sizeof(PyObject *)

为什么从tp_basicsize中删除了额外的list字节是我无法找到的。 (有关可能的解释,请参阅MSeifert的评论)

但是,这基本上是您具体示例的不同之处。 lists还保留了许多已分配的元素,这有助于确定何时再次进行过度分配。

现在,当添加其他元素时,列表确实会执行此过度分配以实现O(1)追加。 这导致更大的尺寸,因为MSeifert在他的回答中很好地涵盖了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值