成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入Python列表的內部實現

開發 后端
本文將介紹列表在 CPython中的實現,因為畢竟Cpython 又是 Python 最為常用的實現。

本文將介紹列表在 CPython中的實現,因為畢竟Cpython 又是 Python 最為常用的實現。

Python 中的列表非常強大,看看它的內部實現機制是怎么樣的,一定非常有趣。

下面是一段 Python 腳本,在列表中添加幾個整數,然后打印列表。

  1. >>> l = [] 
  2.  
  3. >>> l.append(1) 
  4.  
  5. >>> l.append(2) 
  6.  
  7. >>> l.append(3) 
  8.  
  9. >>> l 
  10.  
  11. [1, 2, 3] 
  12.  
  13. >>> for e in l: 
  14.  
  15. ...   print e 
  16.  
  17. ... 
  18.  
  19.  
  20.  
  21.  

可以發現,列表是一個迭代器。

列表對象的 C 語言結構體

Cpython 中的列表實現類似于下面的 C 結構體。ob_item 是指向列表對象的指針數組。allocated 是申請內存的槽的個數。

  1. typedef struct { 
  2.  
  3.     PyObject_VAR_HEAD 
  4.  
  5.     PyObject **ob_item; 
  6.  
  7.     Py_ssize_t allocated; 
  8.  
  9. } PyListObject;  

列表初始化

看看初始化一個空列表的時候發生了什么,例如:l = []。

  1. arguments: size of the list = 0 
  2.  
  3. returns: list object = [] 
  4.  
  5. PyListNew: 
  6.  
  7.     nbytes = size * size of global Python object = 0 
  8.  
  9.     allocate new list object 
  10.  
  11.     allocate list of pointers (ob_item) of size nbytes = 0 
  12.  
  13.     clear ob_item 
  14.  
  15.     set list's allocated var to 0 = 0 slots 
  16.  
  17.     return list object  

要分清列表大小和分配的槽大小,這很重要。列表的大小和 len(l) 的大小相同。分配槽的大小是指已經在內存中分配了的槽空間數。通常分配的槽的大小要大于列表大小,這是為了避免每次列表添加元素的時候都調用分配內存的函數。下面會具體介紹。

Append 操作

向列表添加一個整數:l.append(1) 時發生了什么?調用了底層的 C 函數 app1()。

  1. arguments: list object, new element 
  2.  
  3. returns: 0 if OK, -1 if not 
  4.  
  5. app1: 
  6.  
  7.     n = size of list 
  8.  
  9.     call list_resize() to resize the list to size n+1 = 0 + 1 = 1 
  10.  
  11.     list[n] = list[0] = new element 
  12.  
  13.     return 0  

下面是 list_resize() 函數。它會多申請一些內存,避免頻繁調用 list_resize() 函數。列表的增長模式為:0,4,8,16,25,35,46,58,72,88……

  1. arguments: list object, new size 
  2.  
  3. returns: 0 if OK, -1 if not 
  4.  
  5. list_resize: 
  6.  
  7.     new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6) = 3 
  8.  
  9.     new_allocated += newsize = 3 + 1 = 4 
  10.  
  11.     resize ob_item (list of pointers) to size new_allocated 
  12.  
  13.     return 0  

現在分配了 4 個用來裝列表元素的槽空間,并且***個空間中為整數 1。如下圖顯示 l[0] 指向我們新添加的整數對象。虛線的方框表示已經分配但沒有使用的槽空間。

列表追加元素操作的平均復雜度為 O(1)。

 

繼續添加新的元素:l.append(2)。調用 list_resize 函數,參數為 n+1 = 2, 但是因為已經申請了 4 個槽空間,所以不需要再申請內存空間。再添加兩個整數的情況也是一樣的:l.append(3),l.append(4)。下圖顯示了我們現在的情況。  

 

Insert 操作

在列表偏移量 1 的位置插入新元素,整數 5:l.insert(1,5),內部調用ins1() 函數。

  1. arguments: list object, where, new element 
  2.  
  3. returns: 0 if OK, -1 if not 
  4.  
  5. ins1: 
  6.  
  7.     resize list to size n+1 = 5 -> 4 more slots will be allocated 
  8.  
  9.     starting at the last element up to the offset whereright shift each element 
  10.  
  11.     set new element at offset where 
  12.  
  13.     return 0  

 

虛線的方框依舊表示已經分配但沒有使用的槽空間?,F在分配了 8 個槽空間,但是列表的大小卻只是 5。

列表插入操作的平均復雜度為 O(n)。

Pop 操作

取出列表***一個元素 即l.pop(),調用了 listpop() 函數。在 listpop() 函數中會調用 list_resize 函數,如果取出元素后列表的大小小于分配的槽空間數的一半,將會縮減列表的大小。

  1. arguments: list object 
  2.  
  3. returns: element popped 
  4.  
  5. listpop: 
  6.  
  7.     if list empty: 
  8.  
  9.         return null 
  10.  
  11.     resize list with size 5 - 1 = 4. 4 is not less than 8/2 so no shrinkage 
  12.  
  13.     set list object size to 4 
  14.  
  15.     return last element  

列表 pop 操作的平均復雜度為 O(1)。 

 

可以看到 pop 操作后槽空間 4 依然指向原先的整數對象,但是最為關鍵的是現在列表的大小已經變為 4。

繼續 pop 一個元素。在 list_resize() 函數中,size – 1 = 4 – 1 = 3 已經小于所分配的槽空間大小的一半,所以縮減分配的槽空間為 6,同時現在列表的大小為 3。

可以看到槽空間 3 和 4 依然指向原先的整數,但是現在列表的大小已經變為 3。

 

Remove 操作

Python 的列表對象有個方法,刪除指定的元素: l.remove(5)。底層調用 listremove() 函數。

  1. arguments: list object, element to remove 
  2.  
  3. returns none if OK, null if not 
  4.  
  5. listremove: 
  6.  
  7.     loop through each list element: 
  8.  
  9.         if correct element: 
  10.  
  11.             slice list between element's slot and element's slot + 1 
  12.  
  13.             return none 
  14.  
  15.     return null  

為了做列表的切片并且刪除元素,調用了 list_ass_slice() 函數,它的實現方法比較有趣。我們在刪除列表位置 1 的元素 5 的時候,低位的偏移量為 1 同時高位的偏移量為 2.

  1. arguments: list object, low offset, high offset 
  2.  
  3. returns: 0 if OK 
  4.  
  5. list_ass_slice: 
  6.  
  7.     copy integer 5 to recycle list to dereference it 
  8.  
  9.     shift elements from slot 2 to slot 1 
  10.  
  11.     resize list to 5 slots 
  12.  
  13.     return 0  

列表 remove 操作的復雜度為 O(n)。

 

責任編輯:龐桂玉 來源: Python開發者
相關推薦

2017-05-22 15:42:39

Python字典哈希表

2021-04-27 08:54:43

ConcurrentH數據結構JDK8

2010-07-13 10:13:35

Perl內部函數

2025-04-07 11:10:00

Python列表開發

2021-09-03 09:55:43

架構Yarn內部

2023-11-23 19:30:35

Python編程語言

2017-09-05 08:08:37

asyncio程序多線程

2010-09-25 15:59:54

JVM虛擬機

2021-08-19 16:56:37

Python內存開發

2017-06-13 12:40:47

Python字符串對象

2014-04-23 14:40:06

iOS開發KVO內部實現

2021-08-12 15:45:23

Pythonimport模塊

2016-10-20 08:46:17

2009-11-03 13:33:39

VB.NET對象列表

2015-07-28 10:06:03

C#內部實現剖析

2022-10-26 15:22:31

React組件User組件

2024-07-05 10:47:15

2024-07-11 11:35:08

數組結構內部機制

2010-03-05 13:38:13

Python數據轉換

2024-11-15 06:00:00

Python列表字典
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产丝袜人妖cd露出 | 国产一级一级毛片 | www在线视频 | 成人免费视屏 | 在线成人 | 日本高清视频在线播放 | 91av国产在线视频 | 91精品国产综合久久婷婷香蕉 | 国产欧美日韩综合精品一 | 一区精品视频在线观看 | 欧美一区二区三区在线观看 | 国产日韩欧美在线 | 亚洲精色 | 欧美在线视频不卡 | 国产精品九九九 | 久久精品国产亚洲一区二区三区 | 亚洲 欧美 日韩在线 | 国产日产欧产精品精品推荐蛮挑 | 欧美激情综合五月色丁香小说 | 成人精品啪啪欧美成 | 国产a区| 91天堂网| 久久国产精品精品国产色婷婷 | 国产高清视频一区二区 | 国产欧美精品一区 | 国产精品久久久久久亚洲调教 | 精品视频一区二区三区 | 国产精品高潮呻吟久久av黑人 | 免费一级毛片 | 欧美一二区 | 国产玖玖 | 成av在线| 日韩中文字幕在线播放 | 久精品久久 | 看一级黄色毛片 | 免费成人午夜 | 亚洲美女一区二区三区 | 国产欧美在线一区 | 欧美日韩成人 | 精品视频久久久 | 99亚洲|