python里面的列表 n=n_10 与 n_=10的小区别

原文链接 记一次列表预分配空间的锅

结论

        *不会导致列表扩容,而 *= 会导致数组扩容

举个例子

a = [0]

        a是个列表,我现在想让列表复制10份,用以下两种方案实现

a = a * 10
a *= 10

        实现完以后用sys.getsizeof() 查看两者的字节会发现字节数不同。

       原因在于乘法操作会调用 list_repeat() ;*= 会调用 list_inplace_repeat() 。代码是c语言写的,大概有下面的内容

[listobject.c  v3.6.5]
static PyObject *
list_repeat(PyListObject *a, Py_ssize_t n)
{
    ...
    size = Py_SIZE(a) * n;
    if (size == 0)
        return PyList_New(0);
    np = (PyListObject *) PyList_New(size);  // 创建容纳size个空间的列表
    ...
}

       从这可以看出 list_repeat 需要多少空间就申请多少空间,从这里也可以看出乘法操作是返回一个新的列表对象。

[listobject.c  v3.6.5]
static PyObject *
list_inplace_repeat(PyListObject *self, Py_ssize_t n)
{
    ...
    size = PyList_GET_SIZE(self);
    ...
    if (list_resize(self, size*n) < 0)
        return NULL;
    ...
}

       代码中试图通过 list_resize 来进行扩容,并告诉它这个列表需要容纳 size * n 个元素

[listobject.c  v3.6.5]
static int
list_resize(PyListObject *self, Py_ssize_t newsize)
{
    ...
    new_allocated = newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);
    ...
}

       resize 后的空间 总是 比所需要的大的。按照这里的扩容规则,如果一个空列表通过 append 不断往里面添加元素,那么空间占用会是 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...

       所以这个 *= 会引起列表 resize,而比 * 的方式占用空间大;解释完毕。

原文链接 记一次列表预分配空间的锅

posted on 2021-06-09 19:51  雾恋过往  阅读(90)  评论(0编辑  收藏  举报

Live2D