簡體   English   中英

生成器vs列表理解

[英]generator vs list comprehension

在下面的代碼中,使用列表理解或生成器是否更好?

from itertools import izip
n=2
l=izip(xrange(10**n), xrange(10**n))
print 3 not in [x[0] for x in l]
#or
#print 3 not in (x[0] for x in l)

在這些測試中,如果列表較大,則生成器會更快,如果列表較短,則列表理解顯然會更快。
這是因為理解只是一次計算機嗎?
對於大型列表: 生成器listcomp
對於小列表: 生成器listcomp

in對生成器表達式的使用將使用__iter__()方法並迭代該表達式直到找到匹配項,這使其在一般情況下比列表理解更有效,后者首先會生成整個列表,然后再掃描結果以查找匹配項。

您的特定示例的替代方法是使用any() ,以使測試更加明確。 我覺得這更具可讀性:

any(x[0] == 3 for x in l)

你必須考慮到, in做前進的發電機; 如果還需要在其他地方使用生成器,則不能使用此方法。

至於您的特定計時測試; 您的“短期”測試存在致命缺陷。 izip()生成器的第一個迭代將完全耗盡,從而使其他9999個迭代針對生成器進行測試。 您正在測試在其中創建一個空列表和一個空生成器之間的差異,從而擴大了創建成本的差異。

此外,您應該使用timeit模塊運行測試,確保測試可重復 這意味着您還必須在每次迭代時都創建一個新的izip()對象。 現在,對比度要大得多

>>> # Python 2, 'short'
...
>>> timeit.timeit("l = izip(xrange(10**2), xrange(10**2)); 3 not in (x[0] for x in l)", 'from itertools import izip', number=100000)
0.27606701850891113
>>> timeit.timeit("l = izip(xrange(10**2), xrange(10**2)); 3 not in [x[0] for x in l]", 'from itertools import izip', number=100000)
1.7422130107879639
>>> # Python 2, 'long'
...
>>> timeit.timeit("l = izip(xrange(10**3), xrange(10**3)); 3 not in (x[0] for x in l)", 'from itertools import izip', number=100000)
0.3002200126647949
>>> timeit.timeit("l = izip(xrange(10**3), xrange(10**3)); 3 not in [x[0] for x in l]", 'from itertools import izip', number=100000)
15.624258995056152

在Python 3上:

>>> # Python 3, 'short'
... 
>>> timeit.timeit("l = zip(range(10**2), range(10**2)); 3 not in (x[0] for x in l)", number=100000)
0.2624585109297186
>>> timeit.timeit("l = zip(range(10**2), range(10**2)); 3 not in [x[0] for x in l]", number=100000)
1.5555254180217162
>>> # Python 3, 'long'
... 
>>> timeit.timeit("l = zip(range(10**3), range(10**3)); 3 not in (x[0] for x in l)", number=100000)
0.27222433499991894
>>> timeit.timeit("l = zip(range(10**3), range(10**3)); 3 not in [x[0] for x in l]", number=100000)
15.76974998600781

在所有情況下,生成器變體都快得多; 您必須將“簡短”版本縮短為僅8個元組,列表理解才能開始獲勝:

>>> timeit.timeit("n = 8; l = izip(xrange(n), xrange(n)); 3 not in (x[0] for x in l)", 'from itertools import izip', number=100000)
0.2870941162109375
>>> timeit.timeit("n = 8; l = izip(xrange(n), xrange(n)); 3 not in [x[0] for x in l]", 'from itertools import izip', number=100000)
0.28503894805908203

在Python 3上,生成器表達式和列表推導的實現更加接近了,在列表推導勝出之前,您必須降低4個項目:

>>> timeit.timeit("n = 4; l = zip(range(n), range(8)); 3 not in (x[0] for x in l)", number=100000)
0.284480107948184
>>> timeit.timeit("n = 4; l = zip(range(n), range(8)); 3 not in [x[0] for x in l]", number=100000)
0.23570425796788186

創建生成器比創建列表要慢,因此您必須考慮變量:創建對象的時間和測試表達式的時間。 因此,要回答您的問題,如果“更好”表示“更快”:取決於n

創建生成器表達式會產生很多開銷,但是最終您不需要分配大量內存來彌補它。

小列表理解速度更快,因為它們沒有這些開銷。

通常情況下,小案例足夠接近,因此在這種情況下,最好選擇生成器表達式

在Web服務器上保留可能同時存在100或1000個連接的內存尤為重要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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