1

I am having some trouble to understand what is happening with the following code:

>>> print(list(zip(*[iter((1,2,3,4,5,6,7,8))]*4)))
[(1, 2, 3, 4), (5, 6, 7, 8)]
>>> print(list(zip(*[iter((1,2,3,4,5,6,7))]*4)))
[(1, 2, 3, 4)]

I suspect it is doing internally something like:

>>> print(list(zip(*((1,5), (2,6), (3,7), (4,8)))))
[(1, 2, 3, 4), (5, 6, 7, 8)]

But I can't understand how this list of iterator multiplied by a constant gives this. Could you clarify this for me?

Mauro
  • 237
  • 6
  • 13

1 Answers1

2

What it's doing is equivalent to:

myiter = iter((1,2,3,4,5,6,7,8))
print(list(zip(myiter, myiter, myiter, myiter)))

The original syntax is just using star unpacking with a multiplied list containing four references to the same underlying iterator.

So when zip is pulling the elements for each tuple, it's pulling from the same, stateful iterator for each one, advancing the iterator as it goes. Thus, it gets (1, 2, 3, 4) when pulling the first, second, third and fourth elements for the first tuple.

The call to iter here is important, as is the multiplication; it ensures there is exactly one iterator involved, repeated multiple times, so all the arguments to zip share the same underlying state. If iter() wasn't called, zip would be making its own four independent iterators for the tuple, each of which would advance separately.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • thank you. The key point for me is the phrase: "it's pulling from the same, stateful iterator for each one, advancing the iterator as it goes" – Mauro Jul 27 '20 at 13:47