Lesson 21 · Intermediate · 18 min

Python enumerate and zip

Add positions and pair sequences without manual counters.

enumerateziploop indexesparallel lists

The receipt needs line numbers, and the price list needs items paired with prices. Both are loops with a counter hiding inside. Which built-ins remove the bookkeeping?

Two small built-ins remove a lot of loop bookkeeping. enumerate gives each item a position, and zip walks two or more sequences in parallel. Both return iterators, so wrap them in list() when you want to inspect the result. You will also catch a silent length mismatch, enumerate a lazy iterator, and transpose rows.

Count without a counter

enumerate(colors) yields a pair on each pass: the index and the item. Unpack that pair directly in the for statement. This is clearer than keeping a separate counter and incrementing it by hand.

colors = ["red", "green", "blue"]
for index, color in enumerate(colors):
    print(index, color)

Index and item together

Start counting at one

The start argument changes the first number without changing the sequence. Use start=1 for human-facing numbering such as steps or ranked lists. The original list is not modified.

for number, color in enumerate(["red", "green"], start=1):
    print(f"{number}: {color}")

A human-friendly start

Walk two lists together

zip stops at the shortest input. That is useful when the lists are meant to line up, but it can hide missing data if their lengths differ. Convert the pairs to a list when you need to count or print them as tuples.

names = ["Ada", "Grace"]
scores = [92, 88]
for name, score in zip(names, scores):
    print(f"{name}: {score}")
print(list(zip([1, 2], ["a", "b"])))

Parallel sequences

zip stops silently; strict catches it

zip stops at the shortest input, which is convenient when the sequences really line up and dangerous when a record is missing. strict=True turns a length mismatch into ValueError instead of dropping data. Use it at boundaries where both sides should have the same length.

names = ["Ada", "Grace", "Lin"]
scores = [92, 88]
print(list(zip(names, scores)))
try:
    print(list(zip(names, scores, strict=True)))
except ValueError as error:
    print(type(error).__name__, error)

Silent truncation versus a loud failure

enumerate works on any iterator

enumerate does not need len() or indexing. It pulls one item and produces one pair, so it works with generators, files, and database cursors. Use it when you need a position; do not materialize a large sequence just to count it.

def readings():
    yield 4.5
    yield 3.0
    yield 5.25

for position, value in enumerate(readings(), start=1):
    print(position, value)

Number a lazy stream

Transpose rows with zip(*rows)

zip(*rows) turns a list of rows into columns. It is a compact way to separate names from prices, but every row must have the same width. The result is an iterator of tuples; convert it only when you need to inspect the whole shape.

rows = [("latte", 4.5), ("tea", 3.0), ("mocha", 5.0)]
names, prices = zip(*rows)
print(names)
print(prices)
print(sum(prices))

Rows in, columns out

Key points

  • enumerate yields (index, item) pairs.
  • Use start=1 when the numbers are shown to people.
  • zip walks sequences in parallel and stops at the shortest one.
  • Both functions return iterators, not lists.
  • zip is silent at the shortest input; strict=True makes a mismatch explicit.

Common mistakes

  • Trying to subscript the result of enumerate without converting it to a list.
  • Assuming zip pads shorter inputs with None; it stops instead.
  • Using a manual counter when enumerate already expresses the idea.
  • Assuming equal-length inputs and losing the tail of the longer sequence.
Your turn

Print the names ['Ada', 'Grace'] with 1-based numbers, then print list(zip([1, 2], ['a', 'b'])).

Try it yourself

Change the values, predict the output, then run the code. The Python runtime is downloaded the first time you press Run, so the first run can take a few seconds.

In-browser PythonRuns locally · no account
First run downloads Pyodide from a CDN. Use Run code after editing.

Practice this lesson

12 questions with immediate explanations.

See all 12 answersStart practice
← regexpathlib →