2009-08-29 121 views
4

爲什麼「枚舉」比「xrange + lst [i]」慢?爲什麼Python的枚舉太慢?

 

>>> from timeit import Timer 
>>> lst = [1,2,3,0,1,2]*1000 
>>> setup = 'from __main__ import lst' 
>>> s1 = """ 
for i in range(len(lst)): 
    elem = lst[i] 
""" 
>>> s2 = """ 
for i in xrange(len(lst)): 
    elem = lst[i] 
""" 
>>> s3 = """ 
for i, v in enumerate(lst): 
    elem = v 
""" 
>>> t1 = Timer(s1, setup); t2 = Timer(s2, setup); t3 = Timer(s3, setup) 
>>> t1.timeit(3000), t2.timeit(3000), t3.timeit(3000) 
(1.9263118636586494, 1.6119261665937992, 1.9606022553145719) 
>>> t1.timeit(3000), t2.timeit(3000), t3.timeit(3000) 
(1.93520258859715, 1.6145745478824836, 1.9529405971988041) 
 

編輯: 我記住爲什麼比

for i in xrange(len(lst)): 
    elem = i, lst[i] 

回答

14

如果測量正常,你會看到基本上沒有差別(枚舉在顯微鏡比這個例子中的xrange快,但也內噪聲):

$ python -mtimeit -s'lst=[1,2,3,0,1,2]*1000' 'for i in xrange(len(lst)): elem=lst[i]' 
1000 loops, best of 3: 480 usec per loop 
$ python -mtimeit -s'lst=[1,2,3,0,1,2]*1000' 'for i, elem in enumerate(lst): pass' 
1000 loops, best of 3: 473 usec per loop 

(順便說一句,我總是建議使用timeit在shell提示符是這樣的,而不是在代碼中或解釋器提示符處,因爲輸出的格式和可用性非常好,以及時間單位和所有內容)。

在代碼中,你必須在枚舉情況下,一個額外的任務:您指定的列表項訴for頭子句中,然後重新分配給velem;而在xrange情況下,您只能將該項目分配給elem。當然,在我的情況下,我也只在一種情況下分配一次。爲什麼你想要多次分配?!無論你在循環體內使用elemi做什麼,都可以在我測量的兩種形式中完全相同,只是沒有列舉情況的冗餘。

5

for i, v in enumerate(lst): 
    elem = i, v 
可能是因爲你已經步履蹣跚 enumerate。試試這個:

>>> s3 = """ 
for i, elem in enumerate(lst): 
    pass 
""" 

更新兩個額外的理由使用timeit在shell提示符下亞歷克斯沒有提到:

(1)它做「最好的N」爲您服務。 (2)它會爲你制定出多少次迭代來獲得有意義的結果。

+2

如果不清楚爲什麼John的答案有意義,枚舉產生的結果已包含查找的列表元素。通過在for循環的變量中使用該名稱,可以清楚地說明。在您的原始版本中,您已經執行了兩次查找! – SingleNegationElimination 2009-08-29 22:10:26

+3

@TokenMacGuy和2個評論代號:「已經包含查找到的列表元素......你已經執行了兩次查找」:這是不正確的;該元素僅從列表中提取一次;兩個版本之間的區別是'x = y'形式的多餘分配,它不涉及「查找」。 – 2009-08-29 22:54:55