Python列表怎么进行创建、添加、移除操作
Admin 2022-07-29 群英技术资讯 1117 次浏览
在实际应用中,我们有时候会遇到“Python列表怎么进行创建、添加、移除操作”这样的问题,我们该怎样来处理呢?下文给大家介绍了解决方法,希望这篇“Python列表怎么进行创建、添加、移除操作”文章能帮助大家解决问题。创建列表C语言底层的结构体
lists = []
list.append('name')
list.append('age')
list.append('grade')
typedef struct{
struct _object *_ob_next;
struct _object *_ob_prev; // python内部将对象放在链表进行内存管理
Py_ssize_t ob_refcnt; // 引用计数器,就是多少变量用了它
PyObject **ob_item; // 指针的指针,存列表的元素
Py_ssize_t ob_size; // 已有元素个数
Py_ssize_t allocated; // 列表容量,可容纳个数
} PyListObject;
c源码来自 listobject.c
name_list = [ ]
PyObject *
PyList_New(Py_ssize_t size)
{
PyListObject *op;
size_t nbytes;
#ifdef SHOW_ALLOC_COUNT
static int initialized = 0;
if (!initialized) {
Py_AtExit(show_alloc);
initialized = 1;
}
#endif
// 缓存机制
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();
nbytes = size * sizeof(PyObject *);
if (numfree) {
numfree--;
op = free_list[numfree];
_Py_NewReference((PyObject *)op);
#ifdef SHOW_ALLOC_COUNT
count_reuse++;
#endif
} else {
op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL)
return NULL;Py
#ifdef SHOW_ALLOC_COUNT
count_alloc++;
#endif
}
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; //返回列表的指针
}
list中插入一个元素时,扩容连续的内存地址(容量),在内存创建需要插入的内容p,将地址*p放入list的空间中,所以,PyListObject的ob_item是指针的指针

扩容的曲线一般就是0,4,8,16,24…
// 添加元素
static int
app1(PyListObject *self, PyObject *v)
{
// 获取实际元素个数
Py_ssize_t n = PyList_GET_SIZE(self);
assert (v != NULL);
if (n == PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"cannot add more objects to list");
return -1;
}
// 计算当前容量和内部元素个数
// 直接添加元素/扩容添加
if (list_resize(self, n+1) == -1)
return -1;
// 将元素添加到ob_item,v
Py_INCREF(v);
PyList_SET_ITEM(self, n, v);
return 0;
}
// 扩容机制
// newsize: 已存在元素个数+1
static int
list_resize(PyListObject *self, Py_ssize_t newsize)
{
PyObject **items;
size_t new_allocated;
Py_ssize_t allocated = self->allocated; // 当前的容量
// 1,容量大于个数
// 2,个数大于容量的一半(容量足够且没有内存浪费)
if (allocated >= newsize && newsize >= (allocated >> 1)) {
assert(self->ob_item != NULL || newsize == 0);
Py_SIZE(self) = newsize;
return 0;
}
/*
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/
// 扩容机制的算法
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
/* check for integer overflow */
if (new_allocated > PY_SIZE_MAX - newsize) {
PyErr_NoMemory();
return -1;
} else {
new_allocated += newsize;
}
if (newsize == 0)
new_allocated = 0;
// 扩容/缩容(涉及原来元素的迁移)
items = self->ob_item;
if (new_allocated <= (PY_SIZE_MAX / sizeof(PyObject *)))
PyMem_RESIZE(items, PyObject *, new_allocated);
else
items = NULL;
if (items == NULL) {
PyErr_NoMemory();
return -1;
}
// 赋值,更新个数和容量
self->ob_item = items;
Py_SIZE(self) = newsize;
self->allocated = new_allocated;
return 0;
}
list.pop()
删除最后一个元素只需要修改size,不需要清除数据,下次append可以直接覆盖这个位置
指定索引位置移除后,向前补位
static PyObject *
listpop(PyListObject *self, PyObject *args)
{
Py_ssize_t i = -1;
PyObject *v;
int status;
if (!PyArg_ParseTuple(args, "|n:pop", &i))
return NULL;
if (Py_SIZE(self) == 0) {
/* Special-case most common failure cause */
PyErr_SetString(PyExc_IndexError, "pop from empty list");
return NULL;
}
if (i < 0)
i += Py_SIZE(self);
if (i < 0 || i >= Py_SIZE(self)) {
PyErr_SetString(PyExc_IndexError, "pop index out of range");
return NULL;
}
v = self->ob_item[i];
// 删除最后一个,仅改变size
if (i == Py_SIZE(self) - 1) {
status = list_resize(self, Py_SIZE(self) - 1);
assert(status >= 0);
return v; /* and v now owns the reference the list had */
}
Py_INCREF(v);
// 不是最后一个,需要移动数据位置
status = list_ass_slice(self, i, i+1, (PyObject *)NULL);
assert(status >= 0);
/* Use status, so that in a release build compilers don't
* complain about the unused name.
*/
(void) status;
return v;
}
list.clear()
static int
list_clear(PyListObject *a)
{
Py_ssize_t i;
PyObject **item = a->ob_item;
if (item != NULL) {
i = Py_SIZE(a);
// 各个元素设置为空
Py_SIZE(a) = 0;
a->ob_item = NULL;
a->allocated = 0;
// 引用计数器-1
while (--i >= 0) {
Py_XDECREF(item[i]);
}
PyMem_FREE(item);
}
return 0;
}
del list
销毁列表对象的操作
将列表的引用计数-1
引用计数>0,还有应用的话不做操作
引用计数=0,没人使用
static void
list_dealloc(PyListObject *op)
{
Py_ssize_t i;
// 判断引用计数是否为0
PyObject_GC_UnTrack(op);
Py_TRASHCAN_SAFE_BEGIN(op)
if (op->ob_item != NULL) {
i = Py_SIZE(op);
while (--i >= 0) {
Py_XDECREF(op->ob_item[i]);
}
PyMem_FREE(op->ob_item);
}
// free_list没有80个的话缓存这个list
if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
free_list[numfree++] = op;
else
Py_TYPE(op)->tp_free((PyObject *)op);
Py_TRASHCAN_SAFE_END(op)
}
就是说创建列表时,实际上不会直接开辟内存,而是先看看free_list
# 两次list的地址相同 >>> list1=[1,2,3] >>> id(list1) 69070216L >>> del list1 >>> list2=[0,0,0] >>> id(list2) 69303304L >>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要介绍了Python使用描述符实现属性类型检查,实例属性就是在一个类中将另一个类的实例作为该类的一个数属性,本文通过代码演示给大家介绍的非常详细,需要的朋友可以参考下
Python的命令行调用脚本怎样做的,一些朋友可能会遇到这方面的问题,对此在下文小编向大家来讲解一下,内容详细,易于理解,希望大家阅读完这篇能有收获哦,有需要的朋友就往下看吧!
大家都知道concat()函数可以沿着一条轴将多个对象进行堆叠,其使用方式类似数据库中的数据表合并,在使用merge()函数进行合并时,默认会使用重叠的列索引做为合并键,即取行索引重叠的部分,本文给大家介绍python 数据合并concat函数与merge函数,感兴趣的朋友一起看看吧
小伙伴们日常工作中都必不可少地使用Python实现一些简单的功能,但是不同的人所编写的代码执行效率往往是不同的,下面这篇文章主要给大家介绍了4个Python中高效的技巧,需要的朋友可以参考下
这篇文章主要为大家详细介绍了python实现三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008