为什么itertools.count()与zip一起使用时会消耗额外的元素?

时间:2019-05-20 03:12:55

标签: python functional-programming

我试图通过使用itertools.count()压缩zip来将functools.partial与itertools.count一起使用:

g = functools.partial(zip, itertools.count())

当使用诸如“ abc”,“ ABC”之类的输入调用g时,我注意到itertools.count()神秘地“跳跃”。

我认为我应该得到与直接将zip与itertools.count()使用相同的结果?喜欢:

>>> x=itertools.count();
>>> list(zip("abc",x))
[('a', 0), ('b', 1), ('c', 2)]
>>> list(zip("ABC",x))
[('A', 3), ('B', 4), ('C', 5)]

但是,相反,我得到以下内容-注意g的第二次调用的起始索引是4而不是3:

>>> g = functools.partial(zip, itertools.count())
>>> list(g("abc"))
[(0, 'a'), (1, 'b'), (2, 'c')]
>>> list(g("ABC"))
[(4, 'A'), (5, 'B'), (6, 'C')]

2 个答案:

答案 0 :(得分:5)

请注意,如果您的原始代码以与更改后的代码相同的顺序使用参数,则会得到相同的结果:

>>> x = itertools.count()
>>> list(zip(x, "abc"))
[(0, 'a'), (1, 'b'), (2, 'c')]
>>> list(zip(x, "ABC"))
[(4, 'A'), (5, 'B'), (6, 'C')]

zip()首先尝试其第一个参数,然后尝试其第二个参数,然后再尝试其第三个参数……并在其中一个参数用尽时停止。

在上面的拼写中,"abc"用尽之后,它返回第一个参数,并从3中获得x。但是它的第二个参数已经用尽,因此zip()停止了,3默默地丢失了。

然后继续前进到第二个zip(),并从4中获取x

partial()确实与它无关。

答案 1 :(得分:4)

很容易看出为什么将itertools.count()封装在一个函数中:

def count():
    c = itertools.count()
    while True:
        v = next(c)
        print('yielding', v)
        yield v

g = functools.partial(zip, count())
list(g("abc"))

输出为

yielding 0
yielding 1
yielding 2
yielding 3
[(0, 'a'), (1, 'b'), (2, 'c')]

您将看到zip将评估count()中的下一个参数(这样会产生一个额外的值3),然后才意识到第二个可迭代项中没有其他内容。

作为练习,反转参数,您会发现计算结果有所不同。