概述
list
和 tuple
都是 Python 中提供的陣列資料結構,當我們要建立陣列時,我們需先配置一塊記憶體區段 (其中的每一個區段都會被當成指向實際資料的整數指標),其中 :
-
list
為動態陣列型態 -
tuple
則是靜態陣列 (內容固定不可變的)
list
的可改變大小及修改特性意味著其比tuple
需要存去更多的額外記憶體以計算。
以 list
為例:
1 | list1 = [7, 8, 9, 10, 11] |
在記憶體內的操作即是 :
- 配置
list1
所需要的記憶體空間 - 產生一個空的
list
並存入這些指向元素的 pointer (如list1 = 0x003
)
因此,當我們需要取出 list1 的第 4 個元素時,我們就會透過指標前往該序列,並取出第 4 個貯體位置內容。
串列 (List)
串列的基本操作
1 | year = 2021 |
1 | apple_inf |
list.append
(x) : 將一個新的項目加到 list 的尾端。
list.extend
(iterable)將 iterable(可列舉物件)接到 list 的尾端。
list.insert
(i, x)將一個項目插入至 list 中給定的位置。第一個引數為插入處前元素的索引值,舉例來說:
-
a.insert(0, x)
會插入為 list 首位 -
a.insert(len(a), x)
插入為末位
list.remove
(x)移除列表中第一个值为 x 的元素。
list.pop
([i])移除 list 中給定位置的項目,並回傳它。如果沒有指定位置, a.pop()
將會移除 list 中最後的項目並回傳它。
list.clear
()刪除 list 中所有項目。這等同於 del a[:]
。
list.index
(x[, start[, end]]) 回傳 list 中第一個值等於 x 的項目之索引值(從零開始的索引往後計算)。
1 | _iter = 100000 |
index 於以設定從索引處開始向後搜尋,因此可以看到 t2 的搜尋速度快於 t1
list.count
(x)回傳數值為 x 在 list 中所出現的次數。
list.sort
(***, key=None, reverse=False)將 list 中的項目排序。
list.reverse
()將 list 中的項目前後順序反過來。
1 | apple_inf[2].reverse() |
step 參數指定為 -1 時 可以將 list 的資料順序顛倒。
list.copy()回傳一個淺複製 (shallow copy) 的 list 。等同於 a[:]。
List Comprehensions
listcomp 可以用簡潔的方法創建 list,提高程式易讀性,可用在 iterable 物件。
1 | num = "aeqwFWD" |
1 | num = "aeqwFWD" |
listcomp 將目的表示更為明確,容易理解。
程式超過兩行,使用一般 for 迴圈或許較好。
list
的 超額配置
當你對大小為 N 的串列附加 1 個資料時, python 會建立 N + M 個 額外空間應付未來的附加,接著將舊串列的資料複製到新串列中,再將舊串列銷毀。 (圖 3-3 p.74)
Tuple
雖然 tuple 和 list 看起來很類似,但是他們通常用在不同的情況與不同目的。
tuple 是 immutable (不可變的),通常儲存異質的序列元素,並可經由拆解(unpacking) (請參考本節後段)或索引 (indexing) 來存取(或者在使用 namedtuples 的時候藉由屬性 (attribute) 來存取)。 list 是 mutable (可變的),其元素通常是同質的且可藉由迭代整個串列來存取。
用 Tuple 紀錄
序列封裝 (tuple packing)
1 | metro_area = [ |
序列拆解 (sequence unpacking)
1 | city, year, pop, lat, lon = metro_area[0] |
namedtuple
collection.namedtuple 可以用來製造 tuple 子類別,並加入欄位名稱與類別名稱 (協助除錯)。
1 | from collections import namedtuple |
使用 namedtuple 所用到的記憶體空間與 tuple 完全一樣,使用的記憶體比一般物件少,因為不會儲存到 dict 中的屬性。
1 | metro_area[0].__sizeof__(), tokyo.__sizeof__() |
namedtuple 除了繼承 tuple 屬性以外,最常使用的還包括 _fields 類別屬性, _make(iterable) 類別方法, _asdict() 實例方法
_fields
1 | City._fields |
_make(iterable)
實例化一個 namedtuple
1 | taichung = ['Taichung', 2020 ,23041 , 24.161453, 120.688604] |
_asdict()
回傳 collections.OrderedDict 不是 dict (3.1 到3.7)
回傳 dict (3.8)
1 | tokyo._asdict(), type(tokyo._asdict()) |
將 Tuple 當成不可變的串列
tuple 支援所有不涉及添加或移除的串列方法。
List 與 Tuple 比較
1 | taichung = ['Taichung', 2020 ,23041 , 24.161453, 120.688604] |
以上可以看出,在存取相同元素時, List 的存取大小要比 Tuple 來得大。這是因為 List 為動態存取,需要存取指標來指向對應的元素位置。
1 | kaohsiung = list() |
因為 List 為可變的,一般來說會保留額外的存儲空間,當佔用空間不足時,再額外分配新空間使用。
接著測試 List 與 Tuple 的效能
1 | import timeit |
泛用的程式碼比專門設計來解決特定問題的程式碼要慢得多,因此之後會再詳細說明 .array 與 numpy 方法之比較。