簡體   English   中英

Python列表理解與生成器

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM