python中的列表基於pylistobject實現,列表支援元素的插入、刪除、更新操作,因此pylistobject是乙個變長物件(列表的長度隨著元素的增加和刪除而變長和變短),同時它還是乙個可變物件(列表中的元素根據列表的操作而發生變化,記憶體大小動態的變化),pylistobject的定義:
typedef struct pylistobject;
咋一看pylistobject物件的定義非常簡單,除了通用物件都有的引用計數(ob_refcnt)、型別資訊(ob_type),以及變長物件的長度(ob_size)之外,剩下的只有ob_item,和allocated,ob_item是真正存放列表元素容器的指標,專門有一塊記憶體用來儲存列表元素,這塊記憶體的大小就是allocated所能容納的空間。alloocated是列表所能容納的元素大小,而且滿足條件:
列表物件的建立
pylistob物件的是通過函式pylist_new建立而成,接收引數size,該引數用於指定列表物件所能容納的最大元素個數。
// 列表緩衝池, pylist_maxfreelist為80
static pylistobject *free_list[pylist_maxfreelist];
//緩衝池當前大小
static int numfree = 0;
pyobject *pylist_new(py_ssize_t size)
/* 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) else
if (size <= 0)
op->ob_item = null;
else
memset(op->ob_item, 0, nbytes);
}# 設定ob_size
py_size(op) = size;
op->allocated = size;
_pyobject_gc_track(op);
return (pyobject *) op;
}建立過程大致是:
pylistobject物件的緩衝池
free_list是pylistobject物件的緩衝池,其大小為80,那麼pylistobject物件是什麼時候加入到緩衝池free_list的呢?答案在list_dealloc方法中:
static void
list_dealloc(pylistobject *op)
pymem_free(op->ob_item);
}if (numfree < pylist_maxfreelist && pylist_checkexact(op))
free_list[numfree++] = op;
else
py_type(op)->tp_free((pyobject *)op);
py_trashcan_safe_end(op)
}當pylistobject物件被銷毀的時候,首先將列表中所有程式設計客棧元素的引用計數減一,然後釋放ob_item占用的記憶體,只要緩衝池空間還沒滿,那麼就把該pylistobject加入到緩衝池中(此時pylistobject占用的記憶體並不會正真正**給系統,下次建立pylistobject優先從緩衝池中獲取pylistobject),否則釋放pylistobject物件的記憶體空間。
列表元素插入
設定列表某個位置的值時,如「list[1]=0」,列表的記憶體結構並不會發生變化,而往列表中插入元素時會改變列表的記憶體結構:
static int
ins1(pylistobject *self, py_ssize_t where, pyobject *v)
if (n == py_ssize_t_max)
if (list_resize(self, n+1) == -1)
return -1;
if (where < 0)
if (where > n)
where = n;
items = self->ob_item;
for (i = n; --i >= where; )
items[i+1] = items[i];
py_incref(v);
items[where] = v;
return 0;
}相比設定某個列表位置的值來說,插入操作要多一次pylistobject容量大小的調整,邏輯是list_resize,其次是挪動where之後的元素位置。
// newsize: 列表新的長度
static int
list_resize(pylistobject *self, py_ssize_t newsize)
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
/* check for integer overflow */
if (new_allocated > py_size_max - newsize) else
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)
self->ob_item = items;
py_size(self) = newsize;
self->allocated = new_allocated;
return 0;
}滿足 allocated >= newsize && newsize >= (allocated /2)時,簡單改變list的元素長度,pylistobject物件不會重新分配記憶體空間,否則重新分配記憶體空間,如果newsizeallocatfmjvqzided,就會擴大記憶體空間。當newsize==0時記憶體空間將縮減為0。
總結本文標題: python列表物件實現原理詳解
本文位址:
python列表刪除和多重迴圈退出原理詳解
在學習python的時www.cppcns.com候,會有一些梗非常不適應,在此列舉列表刪除和多重迴圈退出的例子 列表刪除裡面的坑 比如我們有乙個列表裡面有很多相同的值,假如 nums 1,6,6,3,6,2,10,2,100 我想去掉6,可以這樣寫 nums 1,6,6,3,6,2,10,2,10...
Python字典物件實現原理
字典型別是python中最常用的資料型別之一,它是乙個鍵值對的集合,字典通過鍵來索引,關聯到相對的值,理論上它的查詢複雜度是 o 1 d d c 3 d 在字串的實現原理文章中,曾經出現過字典物件用於intern操作,那麼字典的內部結構是怎樣的呢?pydictobject物件就是dict的內部實現。...
Python字典物件實現原理
字典型別是python中最常用的資料型別之一,它是乙個鍵值對的集合,字典通過鍵來索引,關聯到相對的值,理論上它的查詢複雜度是 o 1 d d c 3 d 在字串的實現原理文章中,曾經出現過字典物件用於intern操作,那麼字典的內部結構是怎樣的呢?pydictobject物件就是dict的內部實現。...