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').