So far, our for
loops have iterated over one sequence at a time. But a common programming task is to work with multiple lists in parallel. For example, you might have a list of student names and a corresponding list of their grades, and you want to process them together, pairing the first student with the first grade, the second with the second, and so on.
While you could do this with a manual index, Python provides a much cleaner and more “Pythonic” tool for this job: the built-in zip()
function.
The ‘Old’ Way: Looping with a Manual Index
Before learning about zip()
, a common approach is to use range()
and len()
to generate an index and then use that index to access the items from each list.
students = ["Alice", "Bob", "Charlie"]
scores = [88, 92, 75]
for i in range(len(students)):
student = students[i]
score = scores[i]
print(f"{student} scored {score}.")
This works, but as we discussed in Post #114, it’s not very Pythonic. It’s verbose and forces us to think about index numbers instead of the items themselves.
The Pythonic Solution: The zip()
Function
The zip()
function takes two or more iterables (like lists) and “zips” them together like the teeth of a zipper. It returns an iterator that, on each pass, yields a tuple containing the next item from each of the input lists.
Like map
and filter
, zip()
is “lazy,” meaning it produces these tuples one at a time as you loop over them.
By combining zip()
with tuple unpacking (from Post #60) in our for
loop, we can write much cleaner code.
students = ["Alice", "Bob", "Charlie"]
scores = [88, 92, 75]
for student, score in zip(students, scores):
print(f"{student} scored {score}.")
The output is the same, but the code is far more readable. It clearly states our intent—”for each student and score in the zipped-together lists”—and completely avoids manual index management.
An Important Behavior: zip()
and Uneven Lists
What happens if the lists you are zipping have different lengths? This is a critical behavior to understand.
zip()
stops as soon as the shortest of the input iterables runs out of items.
The extra items in the longer list are simply ignored. zip()
does not raise an error.
list1 = [1, 2, 3, 4, 5] # 5 items
list2 = ["a", "b", "c"] # 3 items
# We convert the zip object to a list to see all its contents at once
zipped_items = list(zip(list1, list2))
print(zipped_items)
The output will only contain three tuples, because the shorter list (list2) only had three items:
[(1, ‘a’), (2, ‘b’), (3, ‘c’)]
What’s Next?
zip()
is an essential tool for any Python programmer. It provides an elegant and efficient way to iterate over multiple sequences in parallel, leading to cleaner and more readable code than manual indexing.
We’ve seen how zip()
can take multiple lists and combine them into a single iterator of tuples. But what if we have the opposite problem? What if we have a list of tuples and want to split them back out into separate lists? This process is called “unzipping,” and it uses a clever trick with the *
operator. In Post #134, we will learn how to reverse the zip()
operation.
Author

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com