簡體   English   中英

比較Python中的兩個生成器

[英]Comparing two generators in Python

我想知道在比較兩台發電機時使用==

例如:

x = ['1','2','3','4','5']

gen_1 = (int(ele) for ele in x)
gen_2 = (int(ele) for ele in x)

gen_1gen_2對於所有實際用途都是相同的,但是當我比較它們時:

>>> gen_1 == gen_2
False

在這里,我的猜測是, ==這里當作is一般的情況,而且由於gen_1gen_2分布在內存的不同地方:

>>> gen_1
<generator object <genexpr> at 0x01E8BAA8>
>>> gen_2
<generator object <genexpr> at 0x01EEE4B8>

他們的比較評估為False 我猜對了嗎? 歡迎任何其他見解。

順便說一句,我知道如何比較兩個發電機:

>>> all(a == b for a,b in zip(gen_1, gen_2))
True

甚至

>>> list(gen_1) == list(gen_2)
True

但如果有更好的方法,我很想知道。

您的猜測是正確的 - 比較未定義的類型的后退==是基於對象標識的比較。

比較它們生成的值的更好方法是

from itertools import izip_longest, tee
sentinel = object()
all(a == b for a, b in izip_longest(gen_1, gen_2, fillvalue=sentinel))

這實際上可以短路而不必查看所有值。 正如larsmans在評論中指出的那樣,我們不能在這里使用izip() ,因為如果生成器生成不同數量的元素,它可能會給出錯誤的結果 - izip()將在最短的迭代器上停止。 我們使用新創建的object實例作為izip_longest()填充值,因為object實例也通過對象標識進行比較,因此保證sentinel與其他所有內容進行比較。

請注意,無法在不更改狀態的情況下比較生成器。 如果以后需要,您可以存儲已消耗的項目:

gen_1, gen_1_teed = tee(gen_1)
gen_2, gen_2_teed = tee(gen_2)
all(a == b for a, b in izip_longest(gen_1, gen_2, fillvalue=sentinel))

這將使gen_1gen_2的狀態基本保持不變。 all()消耗的所有值都存儲在tee對象中。

此時,您可能會問自己,對於手頭的應用程序使用延遲生成器是否真的值得 - 將它們簡單地轉換為列表並使用列表可能更好。

因為生成器按需生成它們的值,所以沒有任何方法可以“比較”它們而不實際消耗它們。 如果您的生成器生成無限的值序列,那么您提出的這種相等性測試將毫無用處。

==確實是一樣is兩個發電機組,因為這是一個可以在不改變其狀態,從而失去了元素進行的唯一檢查。

list(gen_1) == list(gen_2)

是比較兩個有限生成器的可靠和通用的方法(但顯然消耗兩者); 基於zip的解決方案在不生成相同數量的元素時會失敗:

>>> list(zip([1,2,3,4], [1,2,3]))
[(1, 1), (2, 2), (3, 3)]
>>> all(a == b for a, b in zip([1,2,3,4], [1,2,3]))
True

當任一生成器生成無限數量的元素時,基於list的解決方案仍然失敗。 您可以為此設計一種解決方法,但是當兩個生成器都是無限的時,您只能為不相等設計半算法

為了像列表和其他容器一樣對兩個生成器進行逐項比較,Python必須完全消耗它們(好吧,無論如何都要使用它們)。 我認為你必須明確地做到這一點很好,特別是因為一個或另一個可能是無限的。

暫無
暫無

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

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