为什么 python 生成器结果是这样的?

Why does python generator result like this?

代码如下:

def is_subsequence(a, b):
    b = iter(b)
    
    gen = ((i in b) for i in a)
    print(gen)

    for i in gen:
        print(i)

    return all(((i in b) for i in a))

res1 = is_subsequence([1, 3, 5], [1, 2, 3, 4, 5])
res2 = is_subsequence([1, 4, 3], [1, 2, 3, 4, 5])

结果是res1==Falseres2==False。显然 res1 的结果不正确。 当我注释掉 for 循环打印 res1==Trueres2==False 时,这是正确的。 我很困惑。有人可以解释为什么吗?

b 是迭代器时,您遇到的主要问题是表达式 i in b。检查迭代器中的成员资格会迭代这些值。它 returns True 如果找到值(消耗迭代器中的值直到并包括找到的值),或者 False 如果迭代器首先用完。不幸的是,如果您要求迭代器将以错误的顺序产生的值,您很容易错过其中的一些值。这是一个更简单的例子:

b = iter([1,2,3])
print(1 in b) # prints True
print(3 in b) # prints True, but skipped over 2 to get there
print(2 in b) # prints False, since the iterator is exhausted after seeing 3

生成器是惰性迭代器。您可以像列表一样遍历它们,但是一旦这样做,它们就会用完,即什么也没有留下。使用以下行,

gen = ((i in b) for i in a)
print(gen)

您创建一个生成器对象,然后使用以下循环,

for i in gen:
    print(i)

你用尽它。顺便说一下,你在耗尽 gen 的同时也耗尽了 b。所以到最后一行时,b 是空的,所以你的函数总是 return False。

IIUC,你想评估 a 是否是 b 的子序列(不是子集)。所以顺序很重要。您可以将函数更改为:

def is_subsequence(a, b):
    b = iter(b)
    return all(((i in b) for i in a))

它将按预期工作。

输出:

res1 = is_subsequence([1, 3, 5], [1, 2, 3, 4, 5])  # True
res2 = is_subsequence([1, 4, 3], [1, 2, 3, 4, 5])  # False