《Python源码剖析》之 list对象
来源:互联网 发布:windows搭建ftp 编辑:程序博客网 时间:2024/06/16 15:16
定义
typedef struct { PyObject_VAR_HEAD //list对象是变长对象,所以有变长对象头 PyObject **ob_item; //真正的存储容器,用来存储PyObject对象指针。 Py_ssize_t allocated; //allocated表示list已分配了多少存储空间。} PyListObject;
说明
- PyObject_VAR_HEAD
PyListObject是变长对象- PyObject **ob_item;
指向列表元素的指针数组, list[0] 即 ob_item[0]- Py_ssize_t allocated;
allocated列表分配的空间, ob_size为已使用的空间
allocated 总的申请到的内存数量
ob_size 实际使用内存数量
等式:
0 <= ob_size <= allocated
len(list) == ob_size
ob_item == NULL implies ob_size == allocated == 0
构造方法
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 // 大小为负数, return 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(); // 计算需要的字节数(PyObject指针数组) nbytes = size * sizeof(PyObject *); // 如果缓冲池非空, 从缓冲池取 if (numfree) { // 取缓冲池数组最后一个对象 numfree--; op = free_list[numfree]; // set refcnt=1 _Py_NewReference((PyObject *)op);#ifdef SHOW_ALLOC_COUNT count_reuse++;#endif } else { // 否则, GC_New分配内存空间 op = PyObject_GC_New(PyListObject, &PyList_Type); // 分配失败 if (op == NULL) return NULL;#ifdef SHOW_ALLOC_COUNT count_alloc++;#endif } // 确定ob_item列表元素指针的值 // 若大小<=0 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); } // ob_size = size Py_SIZE(op) = size; // allocated op->allocated = size; // gc用 _PyObject_GC_TRACK(op); return (PyObject *) op;}
简化步骤
- 判断列表缓冲池是否为空, 是的话从缓冲池取(复用)
- 否则, 从内存中分配空间
- 然后初始化数据
结论
Py_SIZE(op) = size;
op->allocated = size;
第一次生成list, 其allocated = ob_size
list_resize函数:
int list_resize(PyListObject *self, Py_ssize_t newsize)
用法:
extends方法, list_resize(self, m + n)
pop方法, list_resize(self, Py_SIZE(self) - 1)
append方法, list_resize(self, n+1)
定义:
/*如果allocated / 2 <= newsize <= allocated,则直接把ob_size设置成newsize。如果不在这个范围内,就按如下方案realloc内存:new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);*/if allocated/2 <= newsize <= allocated allocated 不变 ob_size = newsizeelse allocated = newsize + ((newsize >> 3) + (newsize < 9 ? 3 : 6)) ob_size = newsize
List的操作过程
插入元素操作:实质是函数ins1的包装。ins1函数的关键操作是,先通过list_resize(下面细说)调整list长度,然后确定插入点。由于python list的索引可以为负数(即末尾元素索引为-1),所以索引值小于0时得加上长度得到C数组的索引。接着将插入点后的元素向后搬运,在插入点写入对象。从此可以看出list就是C里数组的概念。
插入
- resize n+1
- 确定插入点
- 插入点后所有元素后移
- 执行插入
示例
>>> a = [1, 2, 3]>>> a.insert(0, 9)>>> a[9, 1, 2, 3]
append
- resize n+1
- 放入最后一个位置(ob_size)
示例
>>> a = [1, 2, 3]>>> a.append(4)>>> a[1, 2, 3, 4]
extend
- 计算两个list大小 m n
- resize m+n(此时本身被复制)
- 遍历长度为n的数组, 从ob_item+m的位置开始加入
示例
>>> m = [1, 2, 3]>>> n = [4, 5]>>> m.extend(n)>>> m[1, 2, 3, 4, 5]
删除
- 找到要删除元素位置
- 删除之, 后面元素前移
删除元素操作:实质是函数app1的包装。app1函数的关键操作是,先找到第一个对象的位置,然后通过list_ass_slice函数将删除点前后的两段合并。
示例
>>> a = [1, 2, 3, 2]>>> a.remove(2)>>> a[1, 3, 2]
概念和现实
list的创建分两步。1. 创建list对象本身。2. 为ob_item分配内存。
list的销毁也分两步。1. 回收ob_item的内存。2. 销毁list对象本身。
这样的对象创建和销毁方案是为对象池(free_lists)服务的。
创建list阶段:
Python会查看free_lists中是否有缓存对象。若有,则直接从free_lists取出。若没有,则从堆上分配list对象内存。实际上并没有实现
a=[1,2,3]b=[1,2,3]a is b #输出false !!!
销毁list阶段:
若缓存list数(num_free_lists)小于最大可缓存数(MAXFREELISTS ),则将list对象缓存到free_lists备用。若超过了num_free_lists,则直接释放对象内存。
- 《Python源码剖析》之 list对象
- 《Python 源码剖析》之对象
- 《python源码剖析》笔记 python中的List对象
- Python源码剖析(04 Python中的List对象)
- 《Python源码剖析》之 dict对象
- 《Python源码剖析》阅读笔记:第四章-list对象
- STL之list源码剖析
- STL 之 list 源码剖析
- STL源码剖析之list
- STL之list源码剖析
- 《python源码剖析》笔记 python对象初探
- Python源码剖析(02 Python对象初探)
- 《Python 源码剖析》 之 int
- 《Python源码剖析》之 str
- 《Python 源码剖析》 之 tuple
- STL源码剖析之序列容器list
- 《python源码剖析》之实现small python
- cocos2d-x源码剖析之精灵对象
- C++学习笔记之零碎知识点(一)
- studio中简单的判断网络是否连接
- hdu6166 二进制枚举dijstra
- 面向接口编程(或者面向抽象编程)的一个例子。
- 生成树状菜单(ul-li) 及其 树状下拉列表框
- 《Python源码剖析》之 list对象
- CS229 Lecture notes
- struts2使用笔记
- 如何管理好技术团队的十六点建议
- Pair
- Base64的转码与解码(Java1.8)
- 【stm32f0】stm32 总中断的打开与关闭
- [YTU](2278)判断是否是子串(串) ---字符串匹配(串)
- Http get请求 中文乱码问题