Python列表物件實現原理詳解

2022-09-28 09:12:07 字數 3237 閱讀 8576

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的內部實現。...