日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python 3.8.2 / 内置的数据结构 / list (类似于 STL 中的 vector)

發布時間:2024/10/14 python 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 3.8.2 / 内置的数据结构 / list (类似于 STL 中的 vector) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、特點

(1)相對于 tuple 來說,list 是動態的(mutable),即:各個元素都是可變的。

(2)可以通過索引進行查詢。

(3)list 中的元素可以是 python 中的任何對象。例如:list、tuple、dict、set、字符串和整數,并且可以任意混合。

(4)所有元素由一個中括號“[ ]”包裹。

二、相關操作

1、增

? ? ? ? a、append() ,在 list 尾部插入元素。

? ? ? ? b、insert(),在 list 的指定位置插入元素。

2、刪

? ? ? ? a、pop(),彈出 list 尾部元素并返回,與 append 對應。

? ? ? ? b、remove(),刪除指定元素。

? ? ? ? c、del ,刪除指定的位置的元素。

3、改

? ? ? ? 直接用“=”修改指定元素即可。

4、查

? ? ? ? 類似于數組的索引。

栗子:

if __name__ == '__main__':testlist = ['one', 'two', 'six']# 增# append 在 list 末尾添加元素。testlist.append('three')# insert 在指定的位置插入元素。testlist.insert(1, 'four')# 刪# pop 刪除 list 尾部元素。t = testlist.pop()# remove 刪除 list 中的元素。testlist.remove('two')# del 刪除 list 中指定范圍的元素。del testlist[0:2]# 改testlist[0] = 'hello world!'

三、實現原理

1、底層的實現方式是 PyObject 類型的二維指針數組 。在 python 世界中,一切都是對象,無論是 int 、string 還是 list 等,這些都繼承于 PyObject ,所以 list 保存的是各個 PyObject 的指針,傳指針相對于傳對象效率更高。

2、空 list 的大小是 40B,即:一個描述 list 的結構體的大小。該結構體如下所示:

typedef struct {PyObject_VAR_HEAD // 用來保存已使用的內存槽的數量。PyObject **ob_item; // 用來保存對象的指針的指針數組。Py_ssize_t allocated; // 預先分配的內存槽的總容量,即:ob_item 數組的容量。 } PyListObject;

3、當一個空的 list 執行 append 時,list 實際上會多分配一些內存,這樣可以提高下次 append 的高效性,即:時間復雜度為 O(1)。分配內存的算法如下:

new_allocated = (size_t)newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);

?總體效果是隨著對象的數量增多,單次分配的內存槽逐漸變大。

4、append() 源碼實現

(1)過程簡述

  • 判斷是否需要重新對 list 的內存槽數組(ob_item)進行重新分配。若需要,則申請新的內存槽數組、將舊內存槽數組中的數據拷貝到新的內存槽數組中,釋放舊的內存槽數組。
  • 將新對象的指針加入到 ob_item 的尾部。

(2)append() 函數實際上調用的是 app1() 函數。

/*** 向 list 的尾部添加對象。 */ static PyObject *list_append(PyListObject *self, PyObject *object) {if (app1(self, object) == 0)Py_RETURN_NONE;return NULL; }

(3)app1 函數的執行過程如下:

static int app1(PyListObject *self, PyObject *v) {/*** 返回當前 list 中對象的數量。*/Py_ssize_t n = PyList_GET_SIZE(self);assert(v != NULL);if (n == PY_SSIZE_T_MAX){PyErr_SetString(PyExc_OverflowError,"cannot add more objects to list");return -1;}/*** 重新調整 list 的內存。* 創建新的內存槽數組、釋放舊的內存槽數組。*/if (list_resize(self, n + 1) < 0)return -1;/*** 對象 v 的引用計數 + 1 。*/Py_INCREF(v);/*** 將對象指針插入到 list 的 ob_item 指針數據中。*/PyList_SET_ITEM(self, n, v);return 0; }

(4)精髓就在 list_resize() 函數中了,該函數完成了內存的重新分配。

static int list_resize(PyListObject *self, Py_ssize_t newsize) {PyObject **items;size_t new_allocated, num_allocated_bytes;Py_ssize_t allocated = self->allocated;/* Bypass realloc() when a previous overallocation is large enoughto accommodate the newsize. If the newsize falls lower than halfthe allocated size, then proceed with the realloc() to shrink the list.*//*** (1)若 newsize < 已分配的內存槽的數量的 1/2,則重新分配內存槽數組(縮容)。* (2)若 newsize >= 已分配的內存槽的數量的 1/2,且 newsize =< 已分配的內存槽的數量,則無需調整。* (3)若 newsize > 已分配的內存槽的數量,則重新分配內存槽數組(擴容)。* (注意,新的 list 和舊的 list 不在同一個內存起始地址。)*/if (allocated >= newsize && newsize >= (allocated >> 1)){assert(self->ob_item != NULL || newsize == 0);Py_SIZE(self) = newsize;return 0;}/* This over-allocates proportional to the list size, making room* for additional growth. The over-allocation is mild, but is* enough to give linear-time amortized behavior over a long* sequence of appends() in the presence of a poorly-performing* system realloc().* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...* Note: new_allocated won't overflow because the largest possible value* is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.*//*** 內存分配方案,獲取新的內存槽的數量。*/new_allocated = (size_t)newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);if (new_allocated > (size_t)PY_SSIZE_T_MAX / sizeof(PyObject *)){PyErr_NoMemory();return -1;}if (newsize == 0)new_allocated = 0;/*** 新的內存槽數組的字節總數。*/num_allocated_bytes = new_allocated * sizeof(PyObject *);/*** (1)創建新的內存槽數組;* (2)將舊內存槽數組中的數據拷貝到新的內存槽數組中;* (3)釋放舊的內存槽數組。* obmalloc.c PyMem_realloc() 函數。*/items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes);if (items == NULL){PyErr_NoMemory();return -1;}/*** 將新的狀態更新到 list 對象中。*/self->ob_item = items;Py_SIZE(self) = newsize;self->allocated = new_allocated;return 0; }

5、insert() 源碼實現

(1)過程簡述

  • 判斷是否需要重新對 list 的內存槽數組(ob_item)進行重新分配。若需要,則申請新的內存槽數組、將舊內存槽數組中的數據拷貝到新的內存槽數組中,釋放舊的內存槽數組。
  • 將 where 之后的元素全部向后挪一位。
  • 將 new item 放到 where 的位置上。

(2)append() 函數實際上調用的是 ins1() 函數。

int PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem) {if (!PyList_Check(op)){PyErr_BadInternalCall();return -1;}return ins1((PyListObject *)op, where, newitem); }

(3)ins1() 源碼

static int ins1(PyListObject *self, Py_ssize_t where, PyObject *v) {/*** 返回當前已用的內存槽的數量,即:list 中已有的元素的數量。*/Py_ssize_t i, n = Py_SIZE(self);PyObject **items;if (v == NULL){PyErr_BadInternalCall();return -1;}if (n == PY_SSIZE_T_MAX){PyErr_SetString(PyExc_OverflowError,"cannot add more objects to list");return -1;}/*** 調整內存槽數組。*/if (list_resize(self, n + 1) < 0)return -1;if (where < 0){where += n;if (where < 0)where = 0;}if (where > n)where = n;items = self->ob_item;/*** 將 where 之后的數據向后挪一位。*/for (i = n; --i >= where;)items[i + 1] = items[i];Py_INCREF(v);items[where] = v;return 0; }

四、拓展

下面是兩種創建空 list 的方法,哪一個效率更高呢?

empty_list = [] empty_list = list()

答案是前者效率更高,因為前者是內置的C函數,可以直接調用;后者是 python 的函數調用,會創建 stack 和參數檢查,比較浪費時間。

?

(SAW:Game Over!)

總結

以上是生活随笔為你收集整理的python 3.8.2 / 内置的数据结构 / list (类似于 STL 中的 vector)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。