Built-in function: enumerate() with Efficient Code is one of Python’s best tools for clean, readable, and performant iteration when you need both the item and its position (index). Instead of manually using range(len(iterable)) and indexing (which is error-prone, slower, and less Pythonic), enumerate() pairs each element with its index in one step — faster, safer, and more readable. In 2026, enumerate() remains a core pattern — used everywhere from simple lists to pandas DataFrames, file line numbering, and parallel processing with zip().
Here’s a complete, practical guide to using enumerate() efficiently: why it beats manual indexing, real-world patterns, performance advantages, and modern best practices with type hints and clarity.
The inefficient way uses range(len(...)) — it works but requires extra len() calls and indexing, can cause off-by-one bugs, and is less readable when the iterable is modified.
# Inefficient: manual indexing
my_list = ["apple", "banana", "orange"]
for i in range(len(my_list)):
print(i, my_list[i])
# Efficient: enumerate() — cleaner, faster, safer
for i, item in enumerate(my_list):
print(i, item)
# Output (both):
# 0 apple
# 1 banana
# 2 orange
enumerate() is more efficient because it avoids repeated len() calls and list indexing — it yields pairs directly from the iterable. It also handles modifications to the iterable more safely (though you should still avoid modifying while iterating).
Real-world pattern: numbered output, logging, or building indexed data — enumerate() makes line numbers, row IDs, or positions trivial and readable.
with open("log.txt", "r", encoding="utf-8") as f:
for line_num, line in enumerate(f, start=1):
clean = line.strip()
if "ERROR" in clean.upper():
print(f"Error on line {line_num}: {clean}")
Combine with list comprehensions for indexed results — concise and fast.
# Inefficient: manual range + indexing
indexed = []
for i in range(len(my_list)):
indexed.append((i, my_list[i]))
# Efficient: enumerate() + comprehension
indexed = [(i, item) for i, item in enumerate(my_list)]
print(indexed) # [(0, 'apple'), (1, 'banana'), (2, 'orange')]
# With start=1 for 1-based indexing
indexed_1 = [(i, item) for i, item in enumerate(my_list, start=1)]
print(indexed_1) # [(1, 'apple'), (2, 'banana'), (3, 'orange')]
Best practices make enumerate() code clean, fast, and safe. Prefer enumerate(iterable) over range(len(iterable)) — it’s more readable, avoids off-by-one errors, and is slightly faster (no repeated len() calls). Use start=1 for user-facing or report-style numbering — 0-based is fine internally. Unpack into meaningful names — for line_num, line in enumerate(f): — never for i, x in enumerate(...) unless context is obvious. Avoid modifying the iterable inside the loop — collect changes in a new list to prevent skips or RuntimeError. Modern tip: add type hints for clarity — for i: int, item: str in enumerate(my_list): — improves readability and IDE/mypy support. Combine with zip() for indexed parallel iteration — for i, (a, b) in enumerate(zip(list1, list2), start=1). In production, when enumerating external data (files, APIs), wrap in try/except — handle bad items gracefully without crashing the loop.
enumerate() with efficient code is Python’s go-to for position-aware iteration — clean, fast, and safe. In 2026, use it instead of range(len(...)), with start= for readable numbering, unpacking for clarity, and type hints for safety. Master enumerate(), and you’ll handle lists, files, DataFrames, and sequences with confidence and elegance.
Next time you need both items and their positions — reach for enumerate(). It’s Python’s cleanest way to say: “Give me every element and tell me where it is.”