enumerate and zip are essential Python tools. Here's how to use them.
enumerate
Get index and value together:
# Without enumerate
fruits = ["apple", "banana", "cherry"]
for i in range(len(fruits)):
print(f"{i}: {fruits[i]}")
# With enumerate
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")Start from different index
for i, fruit in enumerate(fruits, start=1):
print(f"{i}: {fruit}")
# 1: apple
# 2: banana
# 3: cherryCommon patterns
# Find index of item
for i, item in enumerate(items):
if item == target:
print(f"Found at index {i}")
break
# Build dict with indices
index_map = {item: i for i, item in enumerate(items)}
# Numbered list
numbered = [f"{i}. {item}" for i, item in enumerate(items, 1)]zip
Iterate over multiple sequences together:
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
# Without zip
for i in range(len(names)):
print(f"{names[i]}: {scores[i]}")
# With zip
for name, score in zip(names, scores):
print(f"{name}: {score}")Multiple sequences
names = ["Alice", "Bob"]
ages = [25, 30]
cities = ["NYC", "LA"]
for name, age, city in zip(names, ages, cities):
print(f"{name}, {age}, from {city}")Unequal lengths
a = [1, 2, 3]
b = [4, 5]
list(zip(a, b)) # [(1, 4), (2, 5)] - stops at shortest
# Use zip_longest for all elements
from itertools import zip_longest
list(zip_longest(a, b, fillvalue=0))
# [(1, 4), (2, 5), (3, 0)]Strict mode (Python 3.10+)
# Raise error if lengths differ
list(zip(a, b, strict=True))
# ValueError: zip() argument 2 is shorter than argument 1Unzipping
pairs = [("a", 1), ("b", 2), ("c", 3)]
# Unzip with *
letters, numbers = zip(*pairs)
# letters = ('a', 'b', 'c')
# numbers = (1, 2, 3)Common patterns
# Create dict from two lists
names = ["a", "b", "c"]
values = [1, 2, 3]
d = dict(zip(names, values))
# {'a': 1, 'b': 2, 'c': 3}
# Transpose matrix
matrix = [[1, 2], [3, 4], [5, 6]]
transposed = list(zip(*matrix))
# [(1, 3, 5), (2, 4, 6)]
# Parallel assignment
for old, new in zip(old_names, new_names):
rename(old, new)Combining enumerate and zip
names = ["Alice", "Bob"]
scores = [85, 92]
for i, (name, score) in enumerate(zip(names, scores)):
print(f"{i}: {name} scored {score}")Performance
Both are lazy iterators—they don't create lists in memory:
# Memory efficient
for i, item in enumerate(huge_list):
process(item)
# If you need a list
indexed = list(enumerate(items))
pairs = list(zip(a, b))My Rules
- Use enumerate over
range(len())— always - Use zip over manual indexing — cleaner code
- Check lengths — zip silently truncates
- Remember they're lazy — convert to list if needed
- Use strict=True — when lengths must match
These two functions appear in almost every Python file I write.
React to this post: