14

I am seeing a strange behavior when working with the zip() function. When I perform the following operation len(list(z)) where z is a zip object, the result is 0 (which seems wrong to me), and the action seems to clear out the zip object. Can someone please help me understand what is going on.

# python3
Python 3.2.3 (default, Sep 30 2012, 16:41:36) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> w = [11, 22, 33, 44, 55, 66]
>>> x = [1, 2, 3, 4]
>>> y = ['a', 'b', 'c']
>>> z = zip(x, y, w)
>>> z
<zip object at 0x7f854f613cb0>
>>> list(z)
[(1, 'a', 11), (2, 'b', 22), (3, 'c', 33)]
>>> len(list(z))
0
>>> list(z)
[]
>>> z
<zip object at 0x7f854f613cb0>
>>> 

Thank you, Ahmed.

mechanical_meat
  • 163,903
  • 24
  • 228
  • 223
Ahmed A
  • 3,362
  • 7
  • 39
  • 57
  • Stack Overflow is really unfriendly to new comers. I think PO's question has its own value since the key point here is that zip in Python3 is generator and I think PO's question is not completely duplicate. – CodingNow May 29 '20 at 05:23

2 Answers2

16

In Python 3 zip is a generator. The generator is being exhausted when you do list(z). You can create a list from the values returned by the generator and operate on that.

l = list(z)
len(l)
# -> 3
l
# -> [(1, 'a', 11), (2, 'b', 22), (3, 'c', 33)]

Generators are a good thing. They allow us to write memory-efficient code in nearly the same way we would write code that deals with lists. To use an example from the linked wiki:

def double(L):
    return [x*2 for x in L]

Could be rewritten as a generator to avoid creating another list in memory:

def double(L):
    for x in L:
        yield x*2
mechanical_meat
  • 163,903
  • 24
  • 228
  • 223
  • 2
    For anyone who is only used to Python 3, in Python 2.x zip returns a list of tuples. – TimothyAWiseman Jan 31 '13 at 23:51
  • 2
    Thanks for adding that. Also Python 3's `zip()` works like 2.x's `itertools.izip()` – mechanical_meat Jan 31 '13 at 23:52
  • Of course, you could just write `double` as `double = (x*2 for x in L)` – Jon Clements Feb 01 '13 at 00:20
  • True. The generator-expression alternative is also mentioned in the wiki. The example is overly simple to highlight the difference -- or lack thereof -- between the list-based approach and the generator-based approach, and is not intended to be used in production code. – mechanical_meat Feb 01 '13 at 00:24
  • It returns an [Iterator](https://docs.python.org/3/c-api/iterator.html) of tuples, which technically is NOT a [Generator](https://docs.python.org/3/c-api/gen.html) (iterators are a superset of generators). [zip() docs from python](https://docs.python.org/3/library/functions.html#zip) – ThisGuyCantEven Jul 17 '22 at 23:01
3

To complete the previous answer, there is a Python library called cardinality for getting the size of iterables.

http://cardinality.readthedocs.io/en/latest/

Eskapp
  • 3,419
  • 2
  • 22
  • 39