enumerate & zip
Two tiny built-in functions fix two of the most common looping headaches: "I need the index and the item" and "I have two lists I want to walk together". enumerate() and zip() make both of these clean, readable, and bug-free.
Learn enumerate & zip in our free Python course — a beginner-friendly interactive lesson with runnable examples, a practice exercise and a quick recall.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Once you have them, you'll never write a manual counter or index-juggling loop again.
The clumsy way is to keep a separate counter and bump it yourself. It works, but it's noisy and easy to get wrong:
enumerate() does the counting for you, handing back the index and the item as a pair on every loop:
The i, fruit on the left is tuple unpacking — enumerate yields (0, "apple") , (1, "banana") , and you unpack each pair into two variables right in the for statement.
For numbered lists that people read, counting from 0 looks odd. The start argument fixes that without changing your data:
When you have related lists — names and scores, questions and answers — zip() pairs them up so you can loop over both at once:
You can zip three or more lists at once — and combine zip with enumerate for index + parallel items:
If the lists are different lengths, zip() simply stops at the shortest one. The extra items are dropped silently:
If you need to reach the end of the longest list and fill the gaps instead, use zip_longest from the itertools module:
Wrapping zip() in dict() is the standard one-liner for turning parallel key and value lists into a dictionary.
zip(*pairs) is the mirror image of zipping — it takes a list of tuples and separates it back into independent columns.
These lines should print a numbered roster pairing names with roles. Reorder them so the output starts with 1. Ada - lead .
Why: both lists (B, D) must exist before zip can pair them. The for header (A) zips and enumerates with start=1 , and the indented print (C) is the loop body. The combined unpacking i, (name, role) reads the index plus each pair.
0 a then 1 b — enumerate works on any iterable, including strings, yielding (index, character) pairs starting at 0.
2 lines ( 1 9 and 2 8 ) — zip stops at the shorter list, so the 3 is never reached.
{" "} — zip pairs the keys with the values and dict() turns those pairs into a dictionary.
Pair countries with medal counts and print a numbered, formatted table.
Lesson complete — your loops just leveled up!
You can grab the index with enumerate() , number lists from 1, walk multiple lists together with zip() , handle mismatched lengths, build dicts, and even unzip data. These two functions replace a lot of fragile manual loops.
🚀 Up next: Checkpoint — Python Essentials — combine everything you've learned into one build.
Practice quiz
What does enumerate(items) yield on each iteration?
- Just the item
- Just the index
- A (index, item) pair
- A (item, index) pair
Answer: A (index, item) pair. enumerate yields tuples of (index, item), letting you unpack both in the for statement.
How do you make enumerate report numbers beginning at 1?
- enumerate(items, start=1)
- enumerate(items, 1) is impossible
- enumerate(items).start(1)
- enumerate(1, items)
Answer: enumerate(items, start=1). The start argument sets the first index reported; start=1 is ideal for human-facing numbered lists.
Does the start argument of enumerate skip any items?
- Yes, it skips the first item
- Yes, it skips start-1 items
- It depends on the iterable
- No, it only changes the reported index; every item is still visited
Answer: No, it only changes the reported index; every item is still visited. start only changes the label; all elements are still iterated over.
When you zip lists of different lengths, zip() stops...
- at the longest list, padding with None
- at the shortest list, ignoring extra items
- and raises a ValueError
- after the first element
Answer: at the shortest list, ignoring extra items. Plain zip() halts at the shortest iterable and silently drops the leftover items of longer ones.
How many lines does print?
- 2
- 1
- 3
- 0
Answer: 2. zip stops at the shorter list (length 2), so it prints '1 9' and '2 8' — 2 lines.
Which tool reaches the end of the LONGEST iterable, filling gaps?
- zip with strict=True
- enumerate
- itertools.zip_longest
- map
Answer: itertools.zip_longest. itertools.zip_longest continues to the longest iterable and pads missing values with fillvalue (None by default).
What does dict(zip(['a', 'b'], [1, 2])) produce?
- a
- b
Answer: b. zip pairs keys with values and dict() turns those pairs into {'a': 1, 'b': 2}.
Given pairs = [('Ada', 88), ('Ben', 72)], what does names, scores = zip(*pairs) give for names?
- Ada
- Ben
zip(*pairs) unzips by position, so names is the tuple ('Ada', 'Ben') and scores is (88, 72).
Can you zip three or more iterables at once?
- No, zip only takes two
- Yes, zip(a, b, c) yields 3-tuples
- Only with itertools
- Only if they are the same length
Answer: Yes, zip(a, b, c) yields 3-tuples. zip accepts any number of iterables and yields tuples with one element from each.
What does produce?
- ('a', 0) then ('b', 1)
- 1 a then 2 b
- 0 a then 1 b
- a b
Answer: 0 a then 1 b. enumerate works on any iterable including strings, yielding (0, 'a') and (1, 'b').