# Zip

It’s often necessary to iterate over multiple lists simultaneously. Suppose we’re keeping score of a game and we have two lists, one for names and one for scores:

``````>>> names = ["Bob", "Alice", "Eve"]
>>> scores = [42, 97, 68]
``````

The `zip` function takes any number of iterable arguments and steps through all of them at the same time until the end of the shortest iterable has been reached:

``````>>> for name, score in zip(names, scores):
>>>     print(f"{name} had a score of {score}.")
...
Bob had a score of 42.
Alice had a score of 97.
Eve had a score of 68.
``````

What will the above loop print after removing the last element from `scores`?

``````>>> scores.pop(-1)
68
>>> for name, score in zip(names, scores):
>>>     print(f"{name} had a score of {score}.")
...
Bob had a score of 42.
Alice had a score of 97.
``````

The loop terminates even though there are more values in `names`. Here, Eve isn’t included because `scores` only has two elements.

We can also use `zip()` to quickly and easily create a `dict` from two lists.

``````>>> names = ["Bob", "Alice", "Eve"]
>>> scores = [42, 97, 68]

>>> score_dict = dict(zip(names, scores))

>>> print(score_dict)
{'Bob': 42, 'Alice': 97, 'Eve': 68}
``````

Note that the result of calling the zip function is actually a generator under the hood. You can only loop over the result of zipping once. If you try to loop over it again, the result will be empty.

``````>>> names = ["Bob", "Alice", "Eve"]
>>> scores = [42, 97, 68]
>>> zip_result = zip(names, scores)

# Works fine the first time!
>>> for name, score in zip_result:
...     print(f"{name} had a score of {score}.")
...
Bob had a score of 42.
Alice had a score of 97.
Eve had a score of 68.

# But empty if we try to loop over it again.
>>> for name, score in zip_result:
...     print(f"{name} had a score of {score}.")
...
>>>
``````