我想知道==在比较两台发电机时的用途
例如:
x = ['1','2','3','4','5']
gen_1 = (int(ele) for ele in x)
gen_2 = (int(ele) for ele in x)
Run Code Online (Sandbox Code Playgroud)
gen_1和gen_2对于所有实际用途都是相同的,但是当我比较它们时:
>>> gen_1 == gen_2
False
Run Code Online (Sandbox Code Playgroud)
我的猜测是,==这里的处理方式与is通常情况相同,因为gen_1和gen_2位于内存的不同位置:
>>> gen_1
<generator object <genexpr> at 0x01E8BAA8>
>>> gen_2
<generator object <genexpr> at 0x01EEE4B8>
Run Code Online (Sandbox Code Playgroud)
他们的比较评估为False.我猜对了吗?欢迎任何其他见解.
顺便说一句,我知道如何比较两个发电机:
>>> all(a == b for a,b in zip(gen_1, gen_2))
True
Run Code Online (Sandbox Code Playgroud)
甚至
>>> list(gen_1) == list(gen_2)
True
Run Code Online (Sandbox Code Playgroud)
但如果有更好的方法,我很想知道.
Sve*_*ach 18
你的猜测是正确的 - 比较未定义的类型的后备==是基于对象身份的比较.
比较它们生成的值的更好方法是
from itertools import izip_longest, tee
sentinel = object()
all(a == b for a, b in izip_longest(gen_1, gen_2, fillvalue=sentinel))
Run Code Online (Sandbox Code Playgroud)
这实际上可以短路而不必查看所有值.正如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))
Run Code Online (Sandbox Code Playgroud)
这将给出状态gen_1并gen_2基本保持不变.消耗的所有值all()都存储在tee对象内.
此时,您可能会问自己,对于手头的应用程序使用延迟生成器是否真的值得 - 将它们简单地转换为列表并使用列表可能更好.
==确实与is两个生成器相同,因为这是唯一可以在不改变状态而丢失元素的情况下进行的检查.
list(gen_1) == list(gen_2)
Run Code Online (Sandbox Code Playgroud)
是比较两个有限生成器的可靠和通用的方法(但显然消耗两者); 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
Run Code Online (Sandbox Code Playgroud)
list当任一生成器生成无限数量的元素时,基于解决方案仍然会失败.您可以为此设计一种解决方法,但是当两个生成器都是无限的时,您只能为不相等设计半算法.
为了对列表和其他容器的两个生成器进行逐项比较,Python必须将它们全部消耗掉(无论如何,较短的生成器)。我认为您必须明确地执行此操作是一件好事,尤其是因为其中一个可能是无限的。