Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why does itertools.count() consume an extra element when used with zip?

I was trying to use functools.partial with itertools.count, by currying zip with itertools.count():

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

When calling g with inputs like "abc", "ABC", I noticed that itertools.count() mysteriously "jumps".

I thought I should get the same result as directly using zip with itertools.count()? like:

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

But instead, I get the following -- notice the starting index at the second call of g is 4 instead of 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')]
like image 993
XXX Avatar asked Oct 30 '25 06:10

XXX


1 Answers

Note that you'd get the same result if your original code used arguments in the same order as your altered code:

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

zip() tries its first argument first, then its second, then its third ... and stops when one of them is exhausted.

In the spelling just above, after "abc" is exhausted, it goes back to the first argument and gets 3 from x. But its second argument is already exhausted, so zip() stops, and the 3 is silently lost.

Then it moves on to the second zip(), and starts by getting 4 from x.

partial() really has nothing to do with it.

like image 181
Tim Peters Avatar answered Nov 01 '25 21:11

Tim Peters