Skip to main content

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}")
warning

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()}")
tip

When enumerating files, using start=1 gives you human-readable line numbers that match what text editors display.

Quick Reference

PatternUse When
for item in iterableYou 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.