1

When doing some simple scripting in python I noticed something strange. Take a look

>>> x=zip((1,2),(3,4))
>>> for i in x:
...     print(x)
...
<zip object at 0x00000284D034F248>
<zip object at 0x00000284D034F248>
>>> for i in x:
...     for k in i:
...             print(k)
...
>>> for i in x:
...     print(x)
...
>>> x=zip((1,2),(3,4))
>>> for i in x:
...     for k in i:
...             print(k)

1
3
2
4

When I print x in the first loop, I get 2 zip objects, as expected. But in the second look I just get nothing, then I run the first loop again and still get nothing, what happened to x?

Then as a check to make sure the second loop does actually work I redefined x and ran it. Please help me understand whats going on. Thanks

user2757771
  • 158
  • 7
  • 1
    try it as a script and not in the terminal and see the difference. – Joseph D. Mar 08 '18 at 04:24
  • @codekaizer there will be no difference. A for loop simply consumes the iterable. After the first loop the iterator is at the end and subsequent iterations will yield nothing. – Wombatz Mar 08 '18 at 04:33
  • @codekaizer: differences of behaviour when executing the same code either in terminal or in a script is quite unusual. In most cases it won't make any difference, and rightly so. – kriss Mar 08 '18 at 04:50
  • @kriss, true. just making sure there's no user error that happened. – Joseph D. Mar 08 '18 at 04:54
  • @codekaizer: it's obvious when you know why it's happening, and you could have tryed it yourself if you liked, no need to ask the OP ;-). If we go that way we could comment on any question asking if the OP is sure it's correct. – kriss Mar 08 '18 at 04:57
  • @kriss, you have a point. :P – Joseph D. Mar 08 '18 at 05:01

1 Answers1

2

The function zip returns an iterator. This means that when your iterate over it, you consume it.

You can see how this happens using next.

x = zip((1,2),(3,4))

next(x) # (1, 3)
next(x) # (2, 4)

next(x) # raises a StopIteration error

So when you loop over x the first time, you fully consume it. When you loop over x the second time, there is nothing more to iterate over.

Here is another example of this behaviour with a loop that only partially consumes a zip object.

x = zip((1, 2, 3),(4, 5, 6))

for y in x:
    print('In first loop:', y)
    break

for y in x:
    print('In second loop:', y)

This prints the following.

In first loop: (1, 4)
In second loop: (2, 5)
In second loop: (3, 6)

If you do not want this behaviour, you can cast the zip object to a list.

x = list(zip((1, 2), (3, 4))) # [(1, 3), (2, 4)]
Olivier Melançon
  • 21,584
  • 4
  • 41
  • 73