I was toying around with the zip() function in python and discovered a problem while using the for loop. Here is my code:
list1 = ['monday', 'tuesday', 'wednesday', 'thursday']
list2 = [1, 2, 3, 4]
zipped_list = zip(list1, list2)
print(*zipped_list) # unpacked zipped list
for a, b in zipped_list: # for this to work comment the print(*zipped_list) statement
print(a, b)
The output for this code is:
('monday', 1) ('tuesday', 2) ('wednesday', 3) ('thursday', 4)
Process finished with exit code 0
Now if I remove the print(*zipped_list) statement then the for loop gets executed correctly:
monday 1
tuesday 2
wednesday 3
thursday 4
Process finished with exit code 0
Why is this happening ?
As pointed out in the first comment, the zip object is consumed with the first print(*zipped_list)
. However, you can convert the zip object to a list first like so to be able to use the values of zip object again:
zipped_list = list(zip(list1, list2))
A zip object is an Iterator
. This Q/A from the link should explain why this happens:
Q: When would I need an extra iterator?
A: Iterator will typically need to maintain some kind of position state information (like the index of the last element returned or the like). If the iterable maintained that state itself, it would become inherently non-reentrant (meaning you could use it only one loop at a time).
Also take a look at the docs for zip. Zip is equivalent to:
def zip(*iterables):
# zip('ABCD', 'xy') --> Ax By
sentinel = object()
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
elem = next(it, sentinel)
if elem is sentinel:
return
result.append(elem)
yield tuple(result)
See the yield statement? This makes it a generator like object. Hence looping over it once exhausts it. Note that just printing the zip object also exhausts it.
Since zip objects are generator like, they produce the elements on demand rather than expand an entire list into memory. The advantage this buys is greater efficiency in their typical use-cases.
Shadowfax answered about the zip generator stuff. If you were wondering why you have new lines...
print(*zipped_list) # => print(elm1, elm2 ,elm3...) now newlines (only one in the end)
But like this:
for a, b in zipped_list:
print(a, b) # each print will do a newline in the end so you have many rows...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With