Python是如何实现列表的
本篇内容主要讲解“Python是如何实现列表的”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python是如何实现列表的”吧!
一、列表结构体创建列表C语言底层的结构体
lists=[]list.append('name')list.append('age')list.append('grade')
typedefstruct{struct_object*_ob_next;struct_object*_ob_prev;//python内部将对象放在链表进行内存管理Py_ssize_tob_refcnt;//引用计数器,就是多少变量用了它PyObject**ob_item;//指针的指针,存列表的元素Py_ssize_tob_size;//已有元素个数Py_ssize_tallocated;//列表容量,可容纳个数}PyListObject;
二、创建列表
name_list = [ ]
PyObject*PyList_New(Py_ssize_tsize){PyListObject*op;size_tnbytes;#ifdefSHOW_ALLOC_COUNTstaticintinitialized=0;if(!initialized){Py_AtExit(show_alloc);initialized=1;}#endif//缓存机制if(size<0){PyErr_BadInternalCall();returnNULL;}/*Checkforoverflowwithoutanactualoverflow,*whichcancausecompilertooptimiseout*/if((size_t)size>PY_SIZE_MAX/sizeof(PyObject*))returnPyErr_NoMemory();nbytes=size*sizeof(PyObject*);if(numfree){numfree--;op=free_list[numfree];_Py_NewReference((PyObject*)op);#ifdefSHOW_ALLOC_COUNTcount_reuse++;#endif}else{op=PyObject_GC_New(PyListObject,&PyList_Type);if(op==NULL)returnNULL;Py#ifdefSHOW_ALLOC_COUNTcount_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);returnPyErr_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…
//添加元素staticintapp1(PyListObject*self,PyObject*v){//获取实际元素个数Py_ssize_tn=PyList_GET_SIZE(self);assert(v!=NULL);if(n==PY_SSIZE_T_MAX){PyErr_SetString(PyExc_OverflowError,"cannotaddmoreobjectstolist");return-1;}//计算当前容量和内部元素个数//直接添加元素/扩容添加if(list_resize(self,n+1)==-1)return-1;//将元素添加到ob_item,vPy_INCREF(v);PyList_SET_ITEM(self,n,v);return0;}
扩容
//扩容机制//newsize:已存在元素个数+1staticintlist_resize(PyListObject*self,Py_ssize_tnewsize){PyObject**items;size_tnew_allocated;Py_ssize_tallocated=self->allocated;//当前的容量//1,容量大于个数//2,个数大于容量的一半(容量足够且没有内存浪费)if(allocated>=newsize&&newsize>=(allocated>>1)){assert(self->ob_item!=NULL||newsize==0);Py_SIZE(self)=newsize;return0;}/**Thegrowthpatternis:0,4,8,16,25,35,46,58,72,88,...*///扩容机制的算法new_allocated=(newsize>>3)+(newsize<9?3:6);/*checkforintegeroverflow*/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);elseitems=NULL;if(items==NULL){PyErr_NoMemory();return-1;}//赋值,更新个数和容量self->ob_item=items;Py_SIZE(self)=newsize;self->allocated=new_allocated;return0;}四、移除元素
list.pop()
删除最后一个元素只需要修改size,不需要清除数据,下次append可以直接覆盖这个位置
指定索引位置移除后,向前补位
staticPyObject*listpop(PyListObject*self,PyObject*args){Py_ssize_ti=-1;PyObject*v;intstatus;if(!PyArg_ParseTuple(args,"|n:pop",&i))returnNULL;if(Py_SIZE(self)==0){/*Special-casemostcommonfailurecause*/PyErr_SetString(PyExc_IndexError,"popfromemptylist");returnNULL;}if(i<0)i+=Py_SIZE(self);if(i<0||i>=Py_SIZE(self)){PyErr_SetString(PyExc_IndexError,"popindexoutofrange");returnNULL;}v=self->ob_item[i];//删除最后一个,仅改变sizeif(i==Py_SIZE(self)-1){status=list_resize(self,Py_SIZE(self)-1);assert(status>=0);returnv;/*andvnowownsthereferencethelisthad*/}Py_INCREF(v);//不是最后一个,需要移动数据位置status=list_ass_slice(self,i,i+1,(PyObject*)NULL);assert(status>=0);/*Usestatus,sothatinareleasebuildcompilersdon't*complainabouttheunusedname.*/(void)status;returnv;}五、清空
list.clear()
staticintlist_clear(PyListObject*a){Py_ssize_ti;PyObject**item=a->ob_item;if(item!=NULL){i=Py_SIZE(a);//各个元素设置为空Py_SIZE(a)=0;a->ob_item=NULL;a->allocated=0;//引用计数器-1while(--i>=0){Py_XDECREF(item[i]);}PyMem_FREE(item);}return0;}六、销毁
del list
销毁列表对象的操作
将列表的引用计数-1
引用计数>0,还有应用的话不做操作
引用计数=0,没人使用
处理列表的元素,将所有引用计数-1(GC回收0计数)
ob_item=0,ob_size=0,ob_allocated=0
将列表从双向链表移除,可以销毁
为了提高效率,Python结束期在内部为free_list缓存80个list,存放无使用的list,再创建的时候直接从缓存中拿来初始化。如果已经存了80个,del 的时候直接在内存中销毁对象
staticvoidlist_dealloc(PyListObject*op){Py_ssize_ti;//判断引用计数是否为0PyObject_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个的话缓存这个listif(numfree<PyList_MAXFREELIST&&PyList_CheckExact(op))free_list[numfree++]=op;elsePy_TYPE(op)->tp_free((PyObject*)op);Py_TRASHCAN_SAFE_END(op)}
就是说创建列表时,实际上不会直接开辟内存,而是先看看free_list
#两次list的地址相同>>>list1=[1,2,3]>>>id(list1)69070216L>>>dellist1>>>list2=[0,0,0]>>>id(list2)69303304L>>>
到此,相信大家对“Python是如何实现列表的”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。