2013-01-02 135 views
4

我試圖找到列表理解的效率,但它看起來像它比正常的函數操作更昂貴。有人可以解釋嗎?Python列表理解昂貴

def squares(values): 
    lst = [] 
    for x in range(values): 
     lst.append(x*x) 
    return lst 

def main(): 
    t = timeit.Timer(stmt="lst = [x*x for x in range(10)]") 
    print t.timeit() 
    t = timeit.Timer(stmt="squares",setup="from __main__ import squares") 
    print t.timeit() 

    lst = [x*x for x in range(10)] 
    print lst 
    print squares(10) 



----Output:--- 
2.4147507644 
0.0284455255965 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 

對於相同的輸出,與列表理解相比,正常函數計算的時間很少。

我認爲列表理解更有效。

+0

下面的答案解釋了您的結果 - 但值得注意的是,爲什麼列表編輯速度更快 - 循環在較低的級別執行,這意味着它可以更有效地完成。 –

+1

@Lattyware:不,循環實際上沒有區別;它是在non-comp版本中調用速度的'.append()'調用。它需要在循環中每次查找和調用,並且每次都爲這一個元素增長列表。 comp可以一次構建列表。 –

回答

20

你永遠不會致電你的squares函數,所以它沒有做任何事情。

列表理解實際上更快:

>>> import timeit 
>>> def squares(values): 
...  lst = [] 
...  for x in range(values): 
...   lst.append(x*x) 
...  return lst 
... 
>>> def squares_comp(values): 
...  return [x*x for x in range(values)] 
... 
>>> timeit.timeit('f(10)', 'from __main__ import squares as f') 
3.9415171146392822 
>>> timeit.timeit('f(10)', 'from __main__ import squares_comp as f') 
2.3243820667266846 

如果使用dis模塊來看看字節碼每個功能,你可以看到爲什麼:

>>> import dis 
>>> dis.dis(squares) 
    2   0 BUILD_LIST    0 
       3 STORE_FAST    1 (lst) 

    3   6 SETUP_LOOP    37 (to 46) 
       9 LOAD_GLOBAL    0 (range) 
      12 LOAD_FAST    0 (values) 
      15 CALL_FUNCTION   1 
      18 GET_ITER    
     >> 19 FOR_ITER    23 (to 45) 
      22 STORE_FAST    2 (x) 

    4   25 LOAD_FAST    1 (lst) 
      28 LOAD_ATTR    1 (append) 
      31 LOAD_FAST    2 (x) 
      34 LOAD_FAST    2 (x) 
      37 BINARY_MULTIPLY  
      38 CALL_FUNCTION   1 
      41 POP_TOP    
      42 JUMP_ABSOLUTE   19 
     >> 45 POP_BLOCK   

    5  >> 46 LOAD_FAST    1 (lst) 
      49 RETURN_VALUE   
>>> dis.dis(squares_comp) 
    2   0 BUILD_LIST    0 
       3 LOAD_GLOBAL    0 (range) 
       6 LOAD_FAST    0 (values) 
       9 CALL_FUNCTION   1 
      12 GET_ITER    
     >> 13 FOR_ITER    16 (to 32) 
      16 STORE_FAST    1 (x) 
      19 LOAD_FAST    1 (x) 
      22 LOAD_FAST    1 (x) 
      25 BINARY_MULTIPLY  
      26 LIST_APPEND    2 
      29 JUMP_ABSOLUTE   13 
     >> 32 RETURN_VALUE   

squares功能在每次迭代中查找列表的.append()方法,並調用它。每次調用時,.append()函數必須將列表增加一個元素。

另一方面,列表理解不需要做那項工作。相反,python使用LIST_APPEND字節碼,它使用C API將新元素附加到列表中,而無需對函數執行查找和python調用。

+0

+1,打我吧。 –

+0

誰應該獎勵我的投票呢?這很難選擇:( –

+3

@ SamuelleMattiuzzo我刪除了我的(沒有點有兩次相同的事情),所以在這一票前面投票 –