python中对list的定义如下:
typedef struct { PyObject_VAR_HEAD PyObject **ob_item; Py_ssize_t allocated; } PyListObject;
来看一下python list是如何被创建的:
PyObject * PyList_New(Py_ssize_t size) { PyListObject *op; size_t nbytes; 。。。。。。。// 省略,判断内存容量是否超标 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; #ifdef SHOW_ALLOC_COUNT count_alloc++; #endif } if (size <= 0) op->ob_item = NULL; else { 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; }
重点我已经用“//重点”出来了(因为加粗和加颜色貌似都不管用 T T),函数一开始会进行判断,看要分配的内存有没有超过内存总量。在没有超标的情况下,大致分两步,第一步是创建PyListObject,python首先会去看看对象池中有没有可用的PylistObject,还有可用的话就直接拿来用,没有了的话那就再new一个出来。第二步是给PylistObject要存储的对象分配内存,然后再去给ob_item赋值。
这样就要涉及到关于list的对象池问题了,用free_list来存储,不同于int和string, python中list的对象池是在list对象deallocate的时候被填充的。
static void list_dealloc(PyListObject *op) { ......//省略释放所指元素的代码 if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) free_list[numfree++] = op; else Py_TYPE(op)->tp_free((PyObject *)op); Py_TRASHCAN_SAFE_END(op) }
现在来看看ob_item,它指向的是一个数组,数组里面存的是指向真正list元素的指针。如果用PyList_new(6)来创建一个对象,并且把第四项设置为100的话,大概会如下图所示:
这是书里面的截图,当然前面几个元素不可能是NULL啦,这里只是演示用而已。
我个人觉得这里直接写100不是很正确,这里面应该也是一个指针,指向的是100这个元素。不知道我的理解对不对?
从下面set_item的带注释代码中可以看到:
int PyList_SetItem(register PyObject *op, register Py_ssize_t i, register PyObject *newitem) { register PyObject *olditem; register PyObject **p; .......//省略 p = ((PyListObject *)op) -> ob_item + i; olditem = *p; *p = newitem;//所以100其实应该是指向100的指针??? Py_XDECREF(olditem); return 0; }
差不多对python list的认识就是这些,有错的请指出哦~