[英]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_1和gen_2對於所有實際用途都是相同的,但是當我比較它們時:
>>> gen_1 == gen_2
False
在這里,我的猜測是, ==
這里當作is
一般的情況,而且由於gen_1和gen_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_1
和gen_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.