2016-10-22 62 views
4

我比較不同的方式追加項目到Python中的列表。我在我的電腦上進行了測試,結果當然會在其他電腦上有所不同。是什麼讓Pythons如此快速地追加列表方法?

選項1:5.80秒只有50,000個項目!

a = [] 
for i in range(50000): 
    a = a + [i] 

選項2:2.27秒10,000,000項

a = [] 
for i in range(10000000): 
    a += [i] 

選項3:1.53秒10,000,000項

a = [] 
for i in range(10000000): 
    a.append(i) 

這是毫不奇怪的選項1是緩慢的,因爲它每次創建列表的新副本。

使用增強賦值運算符的選項2速度要快得多。它修改了原始列表。

但是選項3仍然明顯更快。我期望使用append()方法和增強賦值運算符具有相同的結果。

爲什麼append()方法仍然比+ =運算符快得多?

PS: 我的Python版本:

Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32

據taskinoor的額外開銷,答案由每次循環創建一個新的列表對象[i]引起的。這對我來說似乎很合理。我創建了新的測試代碼,試圖避免在每次迭代中創建一個新對象。是的,它現在速度更快,但仍然沒有使用append()那麼快,因爲現在我又有了額外分配的開銷。但我認爲這證明了任務的重點。

選項4:1.91秒10,000,000項 (選項2的改進版本)

a = [] 
b = [0] 
for i in range(10000000): 
    b[0] = i 
    a += b 
+0

我猜他們在增長底層列表時會分配多少額外空間。 –

+1

您正在創建一個新列表並將其與一個簡單的附加項進行擴展,因此追加速度要快得多也不足爲奇。 –

+0

對於你的編輯,你正在做一個setitem,然後再擴展,這並不令人驚訝。 append執行一項工作並做得很好,從來沒有一個實際的用例可以使用任何其他方法將單個元素附加到列表中。 –

回答

3

第二種方法仍然需要創建臨時列表[i]。看看拆解代碼:

>>> import dis 
>>> def func_2(a, i): 
...  a += [i] 
... 
>>> def func_3(a, i): 
...  a.append(i) 
... 
>>> dis.dis(func_2) 
    2   0 LOAD_FAST    0 (a) 
       3 LOAD_FAST    1 (i) 
       6 BUILD_LIST    1 
       9 INPLACE_ADD   
      10 STORE_FAST    0 (a) 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE   
>>> dis.dis(func_3) 
    2   0 LOAD_FAST    0 (a) 
       3 LOAD_ATTR    0 (append) 
       6 LOAD_FAST    1 (i) 
       9 CALL_FUNCTION   1 
      12 POP_TOP    
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE   
>>> 

第二種方法需要6 BUILD_LIST而第三個則沒有。可能還有其他原因,但這應該是方法3更快的主要原因。

+0

這對我有意義。它是+ =運算符後面的[i],它導致創建新列表對象的開銷。 – David

相關問題