How to Choose between enumerate() and Basic Iteration in Python
Choosing between direct iteration and enumerate() depends on one question: do you need the index of each item?
Basic Iteration for Values Only
When you only need the items themselves, iterate directly over the collection:
fruits = ["Apple", "Banana", "Cherry"]
for fruit in fruits:
print(fruit)
# Apple
# Banana
# Cherry
This is the cleanest and most Pythonic approach when position doesn't matter.
Using enumerate() for Index and Value
When you need both the position and the item, enumerate() provides both efficiently:
fruits = ["Apple", "Banana", "Cherry"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 0: Apple
# 1: Banana
# 2: Cherry
The function returns tuples of (index, item) that you unpack directly in the loop.
Custom Starting Index
By default, indexing starts at 0. Use the start parameter to change this:
fruits = ["Apple", "Banana", "Cherry"]
# Human-readable ranking starting at 1
for rank, fruit in enumerate(fruits, start=1):
print(f"Rank {rank}: {fruit}")
# Rank 1: Apple
# Rank 2: Banana
# Rank 3: Cherry
This is particularly useful for displaying numbered lists to users.
Avoid the range(len()) Anti-Pattern
Coming from C or Java, developers often write index-based loops manually:
fruits = ["Apple", "Banana", "Cherry"]
# ❌ Anti-pattern: manual indexing
for i in range(len(fruits)):
print(f"{i}: {fruits[i]}")
# ✅ Pythonic: enumerate
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
The range(len()) pattern is problematic because:
- It's harder to read
- Requires repeated indexing into the list
- Creates opportunities for off-by-one errors
- Performs slightly worse due to extra index lookups
Practical Use Cases
Modifying Based on Position
items = ["first", "second", "third"]
result = []
for i, item in enumerate(items):
if i == 0:
result.append(item.upper())
else:
result.append(item)
print(result) # ['FIRST', 'second', 'third']
Finding Item Positions
scores = [85, 92, 78, 92, 88]
# Find all positions of highest score
max_score = max(scores)
positions = [i for i, score in enumerate(scores) if score == max_score]
print(f"Max score {max_score} at positions: {positions}")
# Max score 92 at positions: [1, 3]
Processing with Context
lines = ["Header", "Data 1", "Data 2", "Footer"]
for i, line in enumerate(lines):
if i == 0:
print(f"[HEADER] {line}")
elif i == len(lines) - 1:
print(f"[FOOTER] {line}")
else:
print(f"[DATA] {line}")
Enumerating Other Iterables
enumerate() works with any iterable, not just lists:
# Strings
for i, char in enumerate("ABC"):
print(f"{i}: {char}")
# Dictionaries (keys)
data = {"a": 1, "b": 2}
for i, key in enumerate(data):
print(f"{i}: {key}")
# Files
with open("data.txt") as f:
for line_num, line in enumerate(f, start=1):
print(f"Line {line_num}: {line.strip()}")
When enumerating files, using start=1 gives you human-readable line numbers that match what text editors display.
Quick Reference
| Pattern | Use When |
|---|---|
for item in iterable | You only need values |
for i, item in enumerate(iterable) | You need position and value |
for i, item in enumerate(iterable, start=1) | You need 1-based numbering |
Summary
Use direct iteration (for x in list) when you only need values. Use enumerate() when you need positions. Never manually track indices with i = 0; i += 1 or use range(len()) when iterating over sequences. The enumerate() function is cleaner, less error-prone, and clearly communicates your intent.