生成器函数在列表和生成器表达式上的行为不同?

Generator function behaving differently on lists and generator expressions?

所以我写了这个无用的生成器函数,它消耗迭代器的前 4 个元素:

def f(it):
    for _ in range(2):
        for _, x in zip(range(2), it):
            yield x

下面的例子符合我的预期:

y = (x for x in range(4))
for x in f(y):
    print(x)
0
1
2
3

这个例子让我很困惑:

for x in f([0, 1, 2, 3]):
    print(x)
0
1
0
1

为什么两个输出不同?

那是因为列表不是迭代器,它是一个列表。第一种情况发生的是它正在消耗迭代器。在第二种情况下,它是从头开始。你需要做 iter([0, 1, 2, 3]).

列表是可迭代但不是迭代器。如果在传递列表之前从列表创建迭代器,您将看到与生成器表达式相同的行为:

>>> list(f(iter([0, 1, 2, 3])))
[0, 1, 2, 3]

迭代器被迭代消耗,所以当你zip第二次你在迭代器中途时:

>>> i = iter([0, 1, 2, 3])
>>> zip(range(2), i)
[(0, 0), (1, 1)]
>>> zip(range(2), i)
[(0, 2), (1, 3)]
>>> zip(range(2), i)
[]

但是当您 zip 列表时,您会再次启动它,创建一个新的迭代器:

>>> l = [0, 1, 2, 3]
>>> zip(range(2), l)
[(0, 0), (1, 1)]
>>> zip(range(2), l)
[(0, 0), (1, 1)]
>>> zip(range(2), l)
[(0, 0), (1, 1)]