python學習筆記 --- python中list的實現

python中list的實現

  • Author : Jasper Yangpython

  • School : Bupt數據結構

先掛個英文版的原文連接 Laurent Luce's Blog 這個做者仍是能夠的,我又發現了他的另一篇關於dict的實現,後面的博文再進行介紹。app

在python中實現list是十分有趣的事情,list在現實使用中是那麼的強大而使人喜好,因此,下面讓咱們一塊兒來一探究竟。less

>>> l = []
    >>> l.append(1)
    >>> l.append(2)
    >>> l.append(3)
    >>> l
    [1, 2, 3]
    >>> for e in l:
    ...   print e
    ... 
    1
    2
    3

如你所見,list是可迭代的函數

List object C structure

一個list對象在 CPython 中是以以下的數據結構保存的。ob_item存儲了一系列指向數據的指針。allocated裏面存儲的是該list在內存分配的大小(slots)oop

typedef struct {
    PyObject_VAR_HEAD
    PyObject **ob_item;
    Py_ssize_t allocated;
} PyListObject;

List initialization

看看當咱們初始化一個list是會發生什麼,e.g. l =[]post

arguments: size of the list = 0
    returns: list object = []
    PyListNew:
        nbytes = size * size of global Python object = 0
        allocate new list object
        allocate list of pointers (ob_item) of size nbytes = 0
        clear ob_item
        set list's allocated var to 0 = 0 slots
        return list object

很重要的一點,咱們須要注意到 allocated slots (內存分配的空間大小)和list的size的區別。list的size和 len(l) 是同樣的。allocated slots的個數就是內存中分配了得slot(能夠理解成內存的block)個數。你會很常常看到 allocated 比size還要大。這個是爲了不屢次的從新分配內存空間(realloc c函數),後面咱們會介紹更多。spa

Append

咱們往list裏append數據後會發生什麼呢~?c的內置函數 app1()會被調用。翻譯

arguments: list object, new element
returns: 0 if OK, -1 if not
app1:
    n = size of list
    call list_resize() to resize the list to size n+1 = 0 + 1 = 1
    list[n] = list[0] = new element
    return 0

讓咱們來看看這個list_resize()。它超量地分配了比所需的內存更多的內存空間。指針

增加模式以下:0,4,8,16,25,35,46,58,72,88. . .

arguments: list object, new size
returns: 0 if OK, -1 if not
list_resize:
    new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6) = 3
    new_allocated += newsize = 3 + 1 = 4
    resize ob_item (list of pointers) to size new_allocated
    return 0

如今有4個slot分配給了這個list去存儲指針,你能夠看到l[0]指向了咱們剛剛append進去的整數對象。虛線方塊表明了沒用到的slot。

append

We continue by adding one more element: l.append(2). list_resize is called with n+1 = 2 but because the allocated size is 4, there is no need to allocate more memory. Same thing happens when we add 2 more integers: l.append(3), l.append(4). The following diagram shows what we have so far.

咱們繼續append更多元素:l.append(2)。list_resize() 被調用了,n = n + 1。可是由於n仍是小於 allocated = 4 ,因此沒有必要去從新分配內存空間,一樣的咱們繼續append 3 和 4。結果不變。

append2

Insert

讓咱們在位置1的地方插入整數5: l.insert(1,5),ins1() 會被調用。

insert

如今分配的內存slot個數變成了8,這個增加的規律和咱們以前講的如出一轍。

Pop

當咱們使用彈出:l.pop(),listpop()會被調用,而且若是list的size小於allocated的一半時,list會收縮,也就是allocated會變小。

arguments: list object
returns: element popped
listpop:
    if list empty:
        return null
    resize list with size 5 - 1 = 4. 4 is not less than 8/2 so no shrinkage
    set list object size to 4
    return last element

pop

你能夠看到slot 4 仍然指向了原來的整數區域,可是list的size已經縮小了,也就是slot4已經不屬於這個list了。

當咱們再pop一次後發現,size已經小於allocated的一半了,因而allocated變成了6。

Remove

python 的 list 還有個特殊的移除元素的方法:l.remove(5) ,這裏移除的不是第5個slot而是那個指向的值是5的slot。listremove() 會被調用。

arguments: list object, element to remove
returns none if OK, null if not
listremove:
    loop through each list element:
        if correct element:
            slice list between element's slot and element's slot + 1
            return none
    return null

切分list並移除元素(也就是上面代碼中的slice),會調用list_ass_slice()。過程以下。

arguments: list object, low offset, high offset
returns: 0 if OK
list_ass_slice:
    copy integer 5 to recycle list to dereference it
    shift elements from slot 2 to slot 1
    resize list to 5 slots
    return 0

remove

但願大家能從我翻譯的這篇文章中學到東西,提升本身~

paper done 2017/04/21
相關文章
相關標籤/搜索