Python中两个生成器的比较

2024-06-02 05:59:49 发布

您现在位置: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

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


Tags: infalsetrue用法forobjectisgenerator
3条回答

您的猜测是对的–不定义==的类型比较的后备方法是基于对象标识的比较。

比较它们产生的价值的更好方法是

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的解决方案仍然失败。你可以为它设计一个解决方案,但是当两个生成器都是无限的时,你只能为不平等设计一个semi-algorithm

因为生成器按需生成其值,所以如果没有实际的消耗它们,就无法“比较”它们。如果你的生成器生成一个无限的值序列,那么你所建议的这种平等测试将是无用的。

相关问题 更多 >