23

Python 3.2

t = (1, 2, 3)
t2 = (5, 6, 7)
z = zip(t, t2)

for x in z:
    print(x)

Result:

(1, 5)
(2, 6)
(3, 7)

Putting in EXACTLY the same loop immediately after, nothing is printed:

for x in z:
    print(x)

z still exists as <zip object at 0xa8d48ec>. I can even reassign the t, t2 to be zipped again, but then it only works once and only once, again.

Is this how its supposed to work? There's no mention in the docs about this.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
jason
  • 4,721
  • 8
  • 37
  • 45

3 Answers3

25

That's how it works in python 3.x. In python2.x, zip returned a list of tuples, but for python3.x, zip behaves like itertools.izip behaved in python2.x. To regain the python2.x behavior, just construct a list from zip's output:

z = list(zip(t,t2))

Note that in python3.x, a lot of the builtin functions now return iterators rather than lists (map, zip, filter)

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 1
    bit late to the party, but this just had me stumped. It seems crazy that you cannot go back to the start of an iterator and simply using a zip has a modifiable effect. Not easy to understand as Python leads to believe... – Neil Walker Apr 12 '18 at 14:53
  • 2
    @NeilWalker -- Perhaps not, but there are a lot of really great benefits to lazy iteration that python's iterators enable (consider any kind of non-seekable streaming data). You can do a lot of processing with very little system overhead compared to the "everything is a list" perspective of the world. – mgilson Apr 12 '18 at 17:33
11

Because zip returns an iterator in Python 3.x. If you want to re-use it, then make it a list first:

z = list(zip(t, t2))
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
6

zip returns an iterator (in Python 3). You can only iterate over an iterator once. The iterator doesn't vanish when it's out of elements, but iterating over it again gives 0 elements. If you want a list, call list on it:

z = list(zip(t, t2))
user2357112
  • 260,549
  • 28
  • 431
  • 505