Search code examples
pythonlistgenerator

Why does python generator result like this?


Here's the code:

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])

The result is that res1==False and res2==False. Apparently the result for res1 is incorrect. When I comment out the for loop print, res1==True and res2==False, which is correct. I'm confused. Can someone explain why?


Solution

  • Generators are lazy iterators. You can loop over them like a list but once you do, they are exhausted, i.e. nothing is left. With the following line,

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

    you create a generator object and then with the following loop,

    for i in gen:
        print(i)
    

    you exhaust it. Incidentally you also exhaust b while exhausting gen. So by the time of the last line, b is empty, so your function will always return False.

    IIUC, you want to evaluate if a is a subsequence (not subset) of b. So the order matters. You can change your function to:

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

    and it will work as intended.

    Output:

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