Background
The enumerate() function was introduced in Python for convenient and idiomatic iteration over elements of a sequence while simultaneously obtaining the current index. This is particularly important because previously, it was often recommended to manually maintain a separate counter, which was considered less idiomatic and less readable.
Problem
In loops, it is often necessary to know not only the current value but also its index in the sequence. Manually managing indices with a separate variable (i) and calling range(len(seq)) leads to errors (index-value mismatches, code duplication) and reduces readability.
Solution
enumerate() returns a lazy iterator that yields a tuple (index, value) of the current element at each step. It allows for elegant and reliable work with indices:
colors = ['red', 'green', 'blue'] for idx, color in enumerate(colors): print(idx, color)
The iteration starts at zero, but any starting value can be specified:
for idx, color in enumerate(colors, start=1): print(idx, color)
Key Features:
enumerate() works with any iterable sequence, returning a tuple (index, element)start, which can be convenientCan you disable returning the index and only keep the values when using enumerate()?
No, enumerate() always returns pairs (index, value). If only the value is needed, use a regular for loop:
for value in my_list: print(value)
Can you use enumerate() with non-indexable objects like generators?
Yes, enumerate() works with any iterable object, including generators. Indexing will occur in the order values appear:
def mygen(): for i in range(3): yield chr(ord('a')+i) for idx, val in enumerate(mygen()): print(idx, val) # 0 a, 1 b, 2 c
Can you automatically set a starting index different from 0, and what happens with negative values?
Yes, enumerate() has a start argument. If a negative value is passed — indexing will start from that value:
for idx, x in enumerate(['a', 'b', 'c'], start=-3): print(idx, x) # -3 a, -2 b, -1 c
range(len(seq)) instead of enumerate() for iterating over a list — makes the code less idiomatic/readableIn a team maintaining a large codebase, they often use:
for i in range(len(mylist)): process(i, mylist[i])
Pros:
Cons:
After refactoring, they switch to:
for idx, val in enumerate(mylist): process(idx, val)
Pros:
Cons: