[英]Python list comprehension vs generator
我在Python中發現了這個問題Generators vs List Comprehension的性能,我使用timeit代替了cProfile。
from timeit import timeit
import cProfile
print timeit('sum([i for i in range(9999999)])', number=1)
print timeit('sum((i for i in range(9999999)))', number=1)
print cProfile.run('sum([i for i in xrange(9999999)])')
print cProfile.run('sum((i for i in xrange(9999999)))')
結果是
LC timeit 0.728941202164
G timeit 0.643975019455
LC cProfile 3 function calls in 0.751 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.673 0.673 0.751 0.751 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.078 0.078 0.078 0.078 {sum}
None
G cProfile 10000003 function calls in 1.644 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
10000000 0.843 0.000 0.843 0.000 <string>:1(<genexpr>)
1 0.000 0.000 1.644 1.644 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.801 0.801 1.644 1.644 {sum}
我相信生成器應該比列表理解更好,但是為什么在這種情況下結果尚不清楚。 我的問題是哪個更好寫
sum((i for i in list_of_i)) # Which use 1 loop
與
sum([i for i in list_of_i]) # Which seem to took 2 loop: 1 for list create and one for sum
在簡單的情況下,如果沒有理解/生成器,這樣做最快的方法是:
sum(xrange(9999999))
通常,如果需要執行某種操作,需要在理解和生成器表達式之間進行選擇,則可以執行以下操作:
sum(a*b for a, b in zip(c, d))
就我個人而言,我認為生成器表達式(沒有多余的括號1 ) 看起來更好,並且由於可讀性很重要-這超過了兩個表達式之間的任何微性能差異。
生成器通常會因為這種情況而變得更快,因為它們避免創建中間列表(以及與之關聯的內存分配)。 隨着內存分配和列表調整大小需要花費更多時間來處理更大的列表,隨着列表變大,時序差異可能會更加明顯。 但是,情況並非總是如此(在StackOverflow上有很好的記錄, str.join
使用列表比使用CPython中的生成器更快,因為當str.join
獲取生成器時,它仍然會構造列表...)。
1每次將生成器表達式作為唯一參數傳遞給函數時,都可以省略括號-這比您預期的發生得更多...
發電機延遲加載; 您必須撥打電話以獲取每次想要的下一個價值。
sum
是一個聚合函數,它對整個可迭代操作。 您必須具有所有可用的值才能執行其工作。
列表理解工作更快的原因是,只有一個顯式調用才能獲取整個列表,而只有一個顯式操作可以對所有列表求和。 但是,使用生成器時,您必須獲取所有項才能執行其聚合,並且由於存在一百萬個,因此將導致一百萬次調用。
這是渴望表現更好的情況之一。
發電機版本獲勝。 cProfile分析只是為genexp引入了比列表理解更多的開銷,因為它有更多的探查器插入點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.