【问题标题】:Why does python generator result like this?为什么python生成器会这样?
【发布时间】:2021-12-30 07:40:09
【问题描述】:

代码如下:

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==False 和res2==False。显然res1 的结果不正确。 当我注释掉 for 循环打印时,res1==True 和 res2==False,这是正确的。 我很困惑。谁能解释一下原因?

【问题讨论】:

  • 因为你在for i in gen:...时已经消耗了迭代器b。如果您将每个生成器的迭代器分开,例如 b, c = iter(b), iter(b) 和 return all(((i in c) ...) 将正常工作。

标签: python list generator


【解决方案1】:

生成器是惰性迭代器。你可以像列表一样循环遍历它们,但是一旦你这样做了,它们就会筋疲力尽,即什么都没有了。使用以下行,

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

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

for i in gen:
    print(i)

你耗尽它。顺便说一句,您还耗尽了b,同时耗尽了gen。所以到最后一行的时候,b 是空的,所以你的函数总是返回 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

【讨论】:

    【解决方案2】:

    当b 是一个迭代器时,您遇到的主要问题是表达式i in b。检查迭代器中的成员资格会迭代这些值。如果找到值(使用迭代器中的值直到并包括找到的值),则返回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
    

    【讨论】:

    • 我认为这是 OP 的意图。对于a=[1,3,2]; b=[1,2,3],is_subsequence 应该返回False。
    猜你喜欢
    • 2021-11-03
    • 1970-01-01
    • 2014-12-21
    • 1970-01-01
    • 2019-12-28
    • 2018-10-15
    • 2015-03-14
    • 1970-01-01
    相关资源
    最近更新 更多