• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Python列表的长度调节方法(附代码)

python 搞代码 4年前 (2022-01-09) 19次浏览 已收录 0个评论

本文来源gaodai#ma#com搞*!代#%^码$网!篇文章给大家带来的内容是关于Python列表的长度调节方法(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

Python 的列表(list)是一个非常灵活的数组,可以随意调整长度。正是因为这种便利,使得我们会情不自禁地去修改数组以满足我们的需求,其中相比于insert, pop 等等而言, append 用法更常见。

有像这样使用:

>>> test = []>>> test.append(1)>>> test.append({2})>>> test.append([3])>>> print test# 输出 [1, set([2]), [3]]

也有像这样使用的:

test = []for i in range(4):    test.append(i)print test# 输出 [0, 1, 2, 3]

这样用很开心,也很满足。

但其实只要遇到能够动态修改数据长度场景,我们都应该马上反应过来一点,那就是内存管理的问题。

如果运行效率和便捷性同时满足的话,那简直就是大大的福音呀。

然而,上帝为你开启一扇窗的同时肯定也已经关上了一扇门了!

吝啬的初始化

深受预分配知识的熏陶,我们也是觉得 list 在初始化是有分配一定的长度的,要不然每次都申请内存那得多 ”low“ 啊。

然后实际上 list 真的就是这么 ”low“:

import systest = []test_1 = [1]print sys.getsizeof(test)print sys.getsizeof(test_1) - sys.getsizeof(test)# 输出 72     # 空列表内存大小,也是 list 对象的总大小8       # 代表增加一个成员,list 增加的大小

我们的猜测是,list 在定义之后,会预先分配好一个一定大小的池用来塞数据,以避免动不动就申请内存。

但是在上面的实验看出,一个成员的列表,比一个空列表,长度仅仅只是大了 8 字节,如果真的存在这样一个预分配的池,那么在预分配个数之内添加成员,两者的内存大小应该是保持不变才对。

所以可以猜测这块 list 应该是没有这样的一个预分配内存池。这里需要来个实锤

PyObject *PyList_New(Py_ssize_t size){    PyListObject *op;    size_t nbytes;    if (size < 0) {        PyErr_BadInternalCall();        return NULL;    }    /* Check for overflow without an actual overflow,     *  which can cause compiler to optimise out */    if ((size_t)size > PY_SIZE_MAX / sizeof(PyObject *))        return PyErr_NoMemory();            // list对象指针的缓存    if (numfree) {        numfree--;        op = free_list[numfree];        _Py_NewReference((PyObject *)op);    } else {        op = PyObject_GC_New(PyListObject, &PyList_Type);        if (op == NULL)            return NULL;    }        // list 成员的内存申请    nbytes = size * sizeof(PyObject *);    if (size <= 0)        op->ob_item = NULL;    else {        op->ob_item = (PyObject **) PyMem_MALLOC(nbytes);        if (op->ob_item == NULL) {            Py_DECREF(op);            return PyErr_NoMemory();        }        memset(op->ob_item, 0, nbytes);    }    Py_SIZE(op) = size;    op->allocated = size;    _PyObject_GC_TRACK(op);    return (PyObject *) op;}

当我们在执行 test = [1] 时,实际上只做了两件事:

根据成员的数目,构建相应长度的空列表;(上述代码)

一个个将这些成员塞进去;

可能有童鞋会觉得,在塞成员的那一步,说不定会触发什么机制使它变大?

很可惜,因为初始化用的方法是 PyList_SET_ITEM, 所以这里是木有的触发什么机制,只是简单的数组成员赋值而已:

#define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v))

所以整个 list 的初始化,还真的就是木有预分配的内存池,直接按需申请,一个萝卜一个坑,实在得狠;


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Python列表的长度调节方法(附代码)

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址