Python enumerate for index and value pairs
Python enumerate adds a running index to an iterable, returning (index, value) pairs as you loop.
Use it when you need the position of each item, like numbered output or labels.
It’s the built-in pattern for pairing each item with its position across lists, generators, or file lines.
Python Enumerate Example For Numbered Output
Output:
Output will appear here...
Output:
1. ship order
2. email customer
How This Example Works
enumerate(tasks, start=1)pairs each task with its position.start=1makes the numbers human-friendly.- The output shows each task labeled with its number.
Common Pitfalls with Python enumerate
Mistake 1: Forgetting that numbering starts at 0.
for line_no, row in enumerate(rows):
print(f"Line {line_no}: {row['sku']}")
for line_no, row in enumerate(rows, start=1):
print(f"Line {line_no}: {row['sku']}")
Why it happens: enumerate defaults to 0, which is correct for zero-based indexes but confusing for human-facing line numbers.
Mistake 2: Enumerating a dictionary and expecting values.
region_totals = {"west": 1200, "east": 980}
for i, total in enumerate(region_totals):
print(i, total)
region_totals = {"west": 1200, "east": 980}
for i, (region, total) in enumerate(region_totals.items(), start=1):
print(i, region, total)
Why it happens: iterating a dict yields keys, so enumerate pairs indexes with keys unless you loop over .items().
If you want key/value lookup patterns, see the Python dict example.
Mistake 3: Building list(enumerate(...)) for large data.
indexed_rows = list(enumerate(rows, start=1))
for line_no, row in indexed_rows:
print(line_no, row)
for line_no, row in enumerate(rows, start=1):
print(line_no, row)
Why it happens: list() forces all pairs into memory, while enumerate is already lazy and can stream rows.
enumerate vs range(len()): Which to Use
Use enumerate when… | Use range(len()) when… |
|---|---|
| You need the index and the item together. | You only need numeric indexes. |
| You are iterating any iterable, including generators. | You must jump by custom steps or iterate by index only. |
| You want readable loops without manual indexing. | You are working with indices for slicing or random access. |
Rule of thumb: reach for enumerate for index + value; use range(len()) when the index itself is the main thing you need.
If you only need index math, the Python range example goes deeper.
Performance Considerations
enumerate is O(n) and lazy, so it doesn’t allocate an extra list of pairs unless you wrap it with list(). In practice, it’s faster and clearer than calling list.index() inside a loop (which can make the loop O(n^2)). If you only need to label rows, enumerate keeps memory flat while still giving you line numbers.
Other Use Cases for enumerate
Flag error lines while scanning logs.
lines = [
"INFO connected",
"ERROR timeout",
"INFO retry",
]
for line_no, line in enumerate(lines, start=1):
if "ERROR" in line:
print(f"Line {line_no}: {line}")
This keeps the exact line number attached to each error, which speeds up debugging and incident review.
It works the same way for files because enumerate accepts any iterable.
Normalize a list in place by index.
names = [" ada", "grace ", " linus"]
for i, name in enumerate(names):
# Update by index when you need to mutate the list in place.
names[i] = name.strip().title()
print(names)
This keeps the data in the same list while still giving you the index you need to assign back. It is clearer than managing a manual counter and keeps the loop readable.