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 and less efficient), enumerate() pairs each element with its index in one step — faster, safer, and more Pythonic. 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’s better than manual indexing, real-world patterns, performance wins, and modern best practices with type hints and clarity.
The classic inefficient way uses range(len(...)) — it works but requires extra lookups, is less readable, and can lead to off-by-one errors or bugs when modifying the iterable.
# 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. 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.
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.”