The zip() function in Python: complete guide with examples

Discover the zip() function in Python: syntax, practical examples and best practices to efficiently combine multiple iterables.
8 min read
Believemy logo

The zip() function is one of the most powerful and elegant built-in functions in Python. It allows you to combine multiple iterables (lists, tuples, strings, etc.) into a single iterable object of tuples. This function is essential for any Python developer who wants to manipulate data efficiently and pythonically. If you want to master all the subtleties of this language, our complete Python course will allow you to deepen these fundamental concepts.

 

Definition of the zip() function

The zip() function takes one or more iterables as parameters and returns an iterator of tuples. Each tuple contains the corresponding elements from each iterable, grouped by position (index). The first tuple contains the first elements of each iterable, the second tuple contains the second elements, and so on.

The basic syntax of zip() is as follows:

PYTHON
zip(iterable1, iterable2, ...)

This function returns a zip object, which is an iterator. This means it only generates tuples on demand, which is particularly memory-efficient when working with large amounts of data.

Good to know

The zip() function stops as soon as the shortest iterable is exhausted. If you have iterables of different lengths, the extra elements from the longer iterables will be ignored.

 

Practical examples of zip()

Combining two lists

The most common use of zip() is to combine two list in parallel. Here is a simple example:

PYTHON
first_names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]

# Combining the two lists
combined = zip(first_names, ages)

# Converting to list to display the result
print(list(combined))
# Result: [('Alice', 25), ('Bob', 30), ('Charlie', 35)]

You can see that each first name is associated with the corresponding age according to their position in the respective lists.

 

Iterating over multiple lists simultaneously

One of the most frequent use cases of zip() is to iterate over multiple lists at the same time in a for loop:

PYTHON
products = ["Apples", "Bananas", "Oranges"]
prices = [2.50, 1.80, 3.20]
quantities = [10, 15, 8]

for product, p, q in zip(products, prices, quantities):
    total = p * q
    print(f"{product}: {q} units at ${p} = ${total}")

# Result:
# Apples: 10 units at $2.5 = $25.0
# Bananas: 15 units at $1.8 = $27.0
# Oranges: 8 units at $3.2 = $25.6

This approach is much more elegant and readable than using indices to access elements from each list.

 

Creating a dictionary from two lists

The zip() function is particularly useful for creating a dict from two lists, one containing the keys and the other the values:

PYTHON
keys = ["name", "age", "city"]
values = ["Marie", 28, "Paris"]

# Creating the dictionary
person = dict(zip(keys, values))

print(person)
# Result: {'name': 'Marie', 'age': 28, 'city': 'Paris'}

This technique is extremely practical when working with tabular data or when you need to transform data from different sources.

 

Handling iterables of different lengths

As mentioned earlier, zip() stops at the shortest iterable:

PYTHON
list1 = [1, 2, 3, 4, 5]
list2 = ['a', 'b', 'c']

result = list(zip(list1, list2))
print(result)
# Result: [(1, 'a'), (2, 'b'), (3, 'c')]
# Elements 4 and 5 are ignored
Warning

If you need to keep all elements from iterables of different lengths, use itertools.zip_longest() which fills in missing values with a default value (usually None).

 

Using zip_longest for iterables of different lengths

Here is how to use zip_longest() from the itertools module:

PYTHON
from itertools import zip_longest

list1 = [1, 2, 3, 4, 5]
list2 = ['a', 'b', 'c']

result = list(zip_longest(list1, list2, fillvalue="N/A"))
print(result)
# Result: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'N/A'), (5, 'N/A')]

 

Unzipping with zip()

An often overlooked feature is the ability to "unzip" a list of tuples using zip() with the unpacking operator *. This operation reverses the combination process:

PYTHON
pairs = [('Alice', 25), ('Bob', 30), ('Charlie', 35)]

# Unzipping
first_names, ages = zip(*pairs)

print(first_names)  # ('Alice', 'Bob', 'Charlie')
print(ages)         # (25, 30, 35)

The * operator unpacks the list of tuples, then zip() groups the elements by position. The result is a tuple for each "column" of data.

 

Matrix transposition

This unzipping technique is particularly useful for transposing a matrix (swapping rows and columns):

PYTHON
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

# Transposing the matrix
transposed_matrix = list(zip(*matrix))

for row in transposed_matrix:
    print(row)

# Result:
# (1, 4, 7)
# (2, 5, 8)
# (3, 6, 9)

This approach is much more concise than using nested loops.

 

Zip with generators and iterators

The zip() function works perfectly with any type of iterable, including generators created with yield:

PYTHON
def even_numbers(n):
    for i in range(0, n, 2):
        yield i

def odd_numbers(n):
    for i in range(1, n, 2):
        yield i

# Combining two generators
even_odd = zip(even_numbers(10), odd_numbers(10))

for even, odd in even_odd:
    print(f"Even: {even}, Odd: {odd}")

# Result:
# Even: 0, Odd: 1
# Even: 2, Odd: 3
# Even: 4, Odd: 5
# Even: 6, Odd: 7
# Even: 8, Odd: 9

Since zip() also returns an iterator, this combination is very memory-efficient because values are generated on demand.

 

Advanced use cases

Creating consecutive pairs

You can use zip() to create pairs of consecutive elements in a list:

PYTHON
data = [10, 20, 30, 40, 50]

# Creating consecutive pairs
consecutive_pairs = list(zip(data, data[1:]))

print(consecutive_pairs)
# Result: [(10, 20), (20, 30), (30, 40), (40, 50)]

This technique is very useful for calculating differences between consecutive elements or for analyzing time series.

 

Sliding window grouping

You can extend this idea to create sliding windows of any size:

PYTHON
data = [1, 2, 3, 4, 5, 6, 7]

# Windows of size 3
windows = list(zip(data, data[1:], data[2:]))

for window in windows:
    print(f"Window: {window}, Average: {sum(window)/3:.2f}")

# Result:
# Window: (1, 2, 3), Average: 2.00
# Window: (2, 3, 4), Average: 3.00
# Window: (3, 4, 5), Average: 4.00
# Window: (4, 5, 6), Average: 5.00
# Window: (5, 6, 7), Average: 6.00

 

Numbering elements with enumerate and zip

You can combine zip() with enumerate() to get both the index and the combined elements:

PYTHON
names = ["Alice", "Bob", "Charlie"]
scores = [95, 87, 92]

for index, (name, score) in enumerate(zip(names, scores), start=1):
    print(f"{index}. {name}: {score} points")

# Result:
# 1. Alice: 95 points
# 2. Bob: 87 points
# 3. Charlie: 92 points

 

Best practices with zip()

Explicitly convert to list if necessary

Don't forget that zip() returns an iterator, not a list. If you need to access elements multiple times or use list operations, convert it explicitly:

PYTHON
# Bad practice - the iterator is exhausted after first use
result = zip([1, 2], ['a', 'b'])
print(list(result))  # [(1, 'a'), (2, 'b')]
print(list(result))  # [] - empty list because iterator is exhausted

# Good practice - convert immediately if necessary
result = list(zip([1, 2], ['a', 'b']))
print(result)  # [(1, 'a'), (2, 'b')]
print(result)  # [(1, 'a'), (2, 'b')] - still works

 

Check iterable lengths

In Python 3.10+, you can use the strict=True parameter to raise an error if iterables don't have the same length:

PYTHON
# Python 3.10+
list1 = [1, 2, 3]
list2 = ['a', 'b']

try:
    result = list(zip(list1, list2, strict=True))
except ValueError as e:
    print(f"Error: {e}")
# Error: zip() argument 2 is shorter than argument 1

 

Prefer zip() over indices

Always use zip() rather than indices when iterating over multiple lists in parallel. It's more readable and more pythonic:

PYTHON
# Avoid
names = ["Alice", "Bob"]
ages = [25, 30]

for i in range(len(names)):
    print(f"{names[i]} is {ages[i]} years old")

# Prefer
for name, age in zip(names, ages):
    print(f"{name} is {age} years old")

 

Summary table

OperationCodeResult
Combine two listszip([1,2], ['a','b'])[(1,'a'), (2,'b')]
Unzipzip(*pairs)Separate tuples
Create a dictionarydict(zip(keys, values))Dictionary
Different lengthszip_longest()Completes with fillvalue
Strict checkzip(..., strict=True)ValueError if lengths ≠

 

Frequently asked questions

Question

What is the difference between zip() and itertools.zip_longest()?

The zip() function stops as soon as the shortest iterable is exhausted, ignoring the remaining elements from longer iterables. In contrast, itertools.zip_longest() continues until the longest iterable is exhausted, filling in missing values with a default value (by default None, but you can specify another value with the fillvalue parameter).

 

Question

Why does zip() return an iterator instead of a list?

The zip() function returns an iterator for memory efficiency reasons. With an iterator, tuples are generated on demand (lazy evaluation), which is particularly important when working with large datasets. If you need a list, you can simply use list(zip(...)).

 

Question

Can you use zip() with more than two iterables?

Absolutely! The zip() function accepts an unlimited number of iterables. For example, zip(list1, list2, list3, list4) will produce tuples of 4 elements, each coming from the corresponding iterable. This is very useful when you need to process data from multiple sources in parallel.

 

Question

How can I learn to master zip() and other Python functions?

To master zip() and all of Python's built-in functions, regular practice is essential. We recommend following our Python course on Believemy, which covers in depth all the essential functions of the language, with practical exercises and concrete projects to consolidate your knowledge.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.