2012-07-20 246 views
2

我寫了一些非常簡單的測試(我知道,它們不是'結論性',但它們讓我好奇)。我跑了優化和所有的爵士樂。爲什麼Python的'all'函數太慢?

from time import time 

alist = [ 2, 4, 6, 8, 10, 12, 24, 48, 64, 128 ] 

def all_even(alist): 
    for val in alist: 
     if not (val & 1) == 0: 
      return False 
    return True 

def all_even_bad(alist): 
    result = False 
    for val in alist: 
     if not (val & 1) == 0: 
      result = False 
     else: 
      result = True 
    return result 

def main(): 
    start = time() 
    for i in range(1, 10000): 
     all_even(alist) 
    print('All even: {0}'.format(time() - start)) 

    start = time() 
    for i in range(1, 10000): 
     all_even_bad(alist) 
    print('All even bad: {0}'.format(time() - start)) 


    start = time() 
    for i in range(1, 10000): 
     all(val & 1 == 0 for val in alist) 
    print('All one: {0}'.format(time() - start)) 


if __name__ == '__main__': 
    main() 

我得到的結果周圍:

> All even: 2.86299991608 
> All even bad: 3.71399998665 
> All one: 3.89900016785 

它出現在內置的功能不及早擺脫困境?

+2

這裏肯定有什麼可疑的。你只能循環10000次10000個列表。你的時間不應該在幾秒鐘的時間。還要注意,你的all_even_bad函數是完全錯誤的; ^)(它實際上只是檢查最後一個元素)。 – mgilson 2012-07-20 17:21:00

+0

對不起 - 我有一堆測試,但沒有想到發佈所有的代碼。我試圖發佈一個小但可運行的示例。 :) – 2012-07-20 17:22:59

回答

8

all()肯定會提前退出,我認爲行爲差異只是創建生成器所需開銷的結果。

下面是一些證明all()不會退出早:

In [8]: alist = [3] + [0] * 2**20 # alist bigger, with an early odd 

In [10]: %timeit all_even(alist) 
1000000 loops, best of 3: 309 ns per loop 

In [11]: %timeit all_even_bad(alist) 
10 loops, best of 3: 133 ms per loop 

In [12]: %timeit all(val & 1 == 0 for val in alist) 
1000000 loops, best of 3: 891 ns per loop 

注意,即使all()慢於all_even()這裏,它仍然是顯著快於不提前退出函數的版本。

+0

發電機是每次迭代?爲什麼每個循環會比all_even高得多?如果僅僅是對象創造,那麼我認爲它應該只發生一次懲罰。 – 2012-07-20 17:17:25

+0

生成器在每次迭代時生成。與直接循環列表相比,這是一個小的但不變的開銷,就像調用'all_even()'或'all_even_bad()'時那樣。 – 2012-07-20 17:20:46

+0

啊,這很有道理。感謝:D – 2012-07-20 17:22:06

1

由於列表中的所有數字實際上都是偶數,所以它在邏輯上不能提早退出?您撥打all()的開銷可能來自構建generator對象。

2

您沒有測試失敗的元件,因此無法短路。

+0

對不起,我寫了幾個測試(不少),但沒有在這裏包括所有的腳本。 – 2012-07-20 17:14:14