如何在 Python 中建立具有特定大小的列表
Jinku Hu
2023年1月30日
當程式設計師提前知道元素數量時,為列表或陣列預分配儲存空間是程式設計師經常用地方式。
與 C++
和 Java 不同,在 Python 中,你必須使用一些值初始化所有預分配的儲存。通常情況下,開發人員使用假值用於此目的,如 None
、''
、False
和 0
。
Python 提供了幾種建立固定大小列表的方法,每種方法都有不同的效能特徵。
為了比較不同方法的效能,我們將使用 Python 的標準模組 timeit
。它提供了一種方便的方法來測量一小段 Python 程式碼的執行時間。
為列表預分配儲存
第一個也是最快的方法,就是使用*
運算子,它將列表重複指定的次數。
>>> [None] * 10
[None, None, None, None, None, None, None, None, None, None]
一百萬次迭代(timeit
的預設迭代值)大約需要 117 毫秒。
>>> timeit("[None] * 10")
0.11655918900214601
另一種方法是將 range
內建函式與列表推導式一起使用。
>>> [None for _ in range(10)]
[None, None, None, None, None, None, None, None, None, None]
它慢了將近六倍,每百萬次迭代需要 612 毫秒的時間。
>>> timeit("[None for _ in range(10)]")
0.6115895550028654
第三種方法是 list.append()
與 for
迴圈一起使用。
>>> a = []
>>> for _ in range(10):
... a.append(None)
...
>>> a
[None, None, None, None, None, None, None, None, None, None]
使用迴圈是最慢的方法,需要 842 毫秒才能完成一百萬次迭代。
>>> timeit("for _ in range(10): a.append(None)", setup="a=[]")
0.8420009529945673
為其他順序資料結構預分配儲存
由於你要為順序資料結構預先分配儲存空間,因此使用 array
內建資料結構而不是列表可能更有意義。
>>> from array import array
>>> array('i',(0,)*10)
array('i', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
如下所示,此方法僅次於 [None] * 10
。
>>> timeit("array('i',(0,)*10)", setup="from array import array")
0.4557597979946877
讓我們將上述純 Python 方法與 NumPy
用於科學計算的 Python 庫進行比較。
>>> from numpy import empty
>>> empty(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
NumPy 方法每百萬次迭代需要 589 毫秒。
>>> timeit("empty(10)", setup="from numpy import empty")
0.5890094790011062
但是,對於更大量的列表,NumPy 方法將更快。
>>> timeit("[None]*10000")
16.059584009999526
>>> timeit("empty(10000)", setup="from numpy import empty")
1.1065983309963485
結論是,對於小地列表來說,最好使用 [None] * 10
,但在處理更大量的順序資料時切換到 NumPy 的 empty()
。
作者: Jinku Hu