When you loop over a list you often need both the item and its position. Using a manual index (e.g. for i in range(len(items))) works but is easy to get wrong. Python’s built-in enumerate() yields (index, item) pairs and is the preferred way to loop with an index. This guide shows how to use enumerate, optional start value, and when to combine it with other patterns. You should know loops and lists; for more on iterables see enumerate() and iterators and iterables.

1. Why loop with an index?

You need the index when you must update the list in place by position, when you need to report “item at position 3”, or when you are building a new structure that depends on position (e.g. “every second element”). For simple iteration over values, a plain for item in items: is enough. For “position + value”, enumerate is clearer and less error-prone than range(len(...)).

2. Basic enumerate()

enumerate(iterable, start=0) returns an iterator of (index, item) tuples. The index starts at 0 by default. Unpack in the loop with for i, x in enumerate(items):.

fruits = ["apple", "banana", "cherry"]
for i, x in enumerate(fruits):
    print(i, x)
# 0 apple
# 1 banana
# 2 cherry

3. Custom start value

Use start=1 (or any integer) when you want human-friendly positions (1-based) for display or reporting. The index is still just a number; it does not change how list indexing works (lists are always 0-based).

for i, name in enumerate(fruits, start=1):
    print(f"{i}. {name}")
# 1. apple
# 2. banana
# 3. cherry

4. Using the index to modify or look up

You can use the index to update the list in place (items[i] = new_value), to look up a parallel list, or to skip every nth item. Be careful not to change the list’s length while iterating (e.g. deleting by index) or you may get IndexError or skip elements. Prefer building a new list or iterating in reverse if you need to remove items.

# Double every value at an even index
nums = [1, 2, 3, 4, 5]
for i, x in enumerate(nums):
    if i % 2 == 0:
        nums[i] = x * 2
# [2, 2, 6, 4, 10]

5. Alternatives: range(len(...)) and zip

for i in range(len(items)): gives you only the index; use items[i] to get the value. It works but is more verbose and easier to mistype. Use enumerate unless you have a reason not to. When you need to loop over two lists in parallel, use zip; when you need index and value from one list, use enumerate.

6. Next steps

See enumerate() for more detail and lists for methods that use indices (e.g. insert, pop). For filtering or transforming lists see filter a list and map over a list. When you see IndexError: list index out of range, check that your index is within 0 .. len(list)-1.