enumerate()
enumerate() wraps any iterable and yields (index, item) pairs, giving you a running count alongside each value. It is the Pythonic replacement for looping over range(len(...)) and indexing back in.
Definition
enumerate() takes an iterable and returns an enumerate object — a lazy iterator that yields a (count, item) tuple for each element. The count is a running index that starts at 0 by default and increases by one on every step, so the first pair is (0, first_item), the next (1, second_item), and so on. It is the standard way to loop over a sequence when you need both the position and the value.
The pairs are designed for tuple unpacking directly in a for header: for i, x in enumerate(seq) binds i to the index and x to the item on each pass. Like range(), the result is lazy — it produces pairs on demand rather than building them all up front — so it is memory-efficient even over a huge or infinite iterable. Any iterable works: lists, tuples, strings, files, generators.
Syntax
enumerate(iterable)
enumerate(iterable, start=0)
for index, item in enumerate(iterable, start=0):
...
Called with one argument, enumerate() counts from 0. Pass a second argument (or the keyword start=) to choose the first index — start=1 is common when you want human-friendly "item 1, item 2" numbering. The start value shifts the count only; it never changes which items are visited or their order.
Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
iterable | Yes | — | Any object that can be iterated — a list, tuple, string, file, generator, or other iterable. Its items are yielded in order, each paired with a running count. |
start | No | 0 | The value the index count begins at. Often passed as start=1 for one-based numbering. Affects the count only, not which items appear. |
iterable is consumed lazily: enumerate() pulls one item from it per step, so passing a generator or a file object streams through it without loading everything into memory. start may be any integer, including a negative one; each yielded index is simply start plus the number of items seen so far.
Return value
An enumerate object — a lazy iterator that yields (index, item) tuples.
- Each tuple is
(index, item): the running count first, the value from the iterable second. - The index starts at
start(default0) and increases by one for every item. - It is lazy — pairs are produced on demand, so it works over large or streaming iterables without materialising them.
- Wrap it in
list(enumerate(seq))to get a concrete list of(index, item)tuples.
Examples
Every example below runs standalone.
Index and value together
The canonical use — unpack both in the loop header.
letters = ["a", "b", "c"]
for i, letter in enumerate(letters):
print(i, letter) # 0 a, 1 b, 2 c
Start counting at one
Pass start=1 for human-friendly numbering.
tasks = ["wake", "code", "sleep"]
for n, task in enumerate(tasks, start=1):
print(n, task) # 1 wake, 2 code, 3 sleep
Materialise the pairs
Wrap in list() to see the (index, item) tuples.
print(list(enumerate(["x", "y"]))) # [(0, 'x'), (1, 'y')]
Avoids the range(len(...)) anti-pattern
Both loops below print the same thing, but the enumerate form is clearer and immune to indexing mistakes.
seq = ["a", "b", "c"]
# clumsy: index back into the sequence
for i in range(len(seq)):
print(i, seq[i])
# idiomatic: enumerate hands you both
for i, x in enumerate(seq):
print(i, x)
Enumerate the characters of a string
A string is an iterable of its characters, so enumerate() pairs each character with its position.
for i, ch in enumerate("cat"):
print(i, ch) # 0 c / 1 a / 2 t
vowels = [i for i, ch in enumerate("beautiful") if ch in "aeiou"]
print(vowels) # [1, 2, 3, 5, 7]
print(list(enumerate("hi"))) # [(0, 'h'), (1, 'i')]
Build a dict of index to item
Because enumerate() yields (index, item) pairs, feeding it to dict() gives a position lookup table in one line.
colors = ["red", "green", "blue"]
lookup = dict(enumerate(colors))
print(lookup) # {0: 'red', 1: 'green', 2: 'blue'}
print(lookup[2]) # blue
Find the position of the first match
Loop with enumerate() and stop at the first item that satisfies a test — you get its index without a separate counter.
nums = [4, 8, 15, 16, 23]
for i, n in enumerate(nums):
if n > 10:
print("first > 10 at index", i) # first > 10 at index 2
break
Number lines with a custom start
start=1 turns the count into human-friendly line numbers; the argument shifts only the index, not the items.
lines = ["import os", "print(os.getcwd())"]
for n, line in enumerate(lines, start=1):
print(f"{n:>2}: {line}") # ' 1: import os' / ' 2: print(os.getcwd())'
Browser & runtime support
enumerate() vs range(len(...))
Before you reach for range(len(seq)), ask whether you need the item — you almost always do. Indexing back in with seq[i] is more to read, easy to get wrong (an off-by-one, or forgetting the item is what you actually wanted), and slower to grasp. enumerate() states the intent directly: give me each item *and* its position.
| enumerate(seq) | range(len(seq)) | |
|---|---|---|
| Yields | (index, item) pairs | just the index |
| Item access | already unpacked | seq[i] — extra indexing |
| Readability | clear intent | noisier, error-prone |
| Use when | you need index and value | you truly need only the index |
Availability
enumerate() is a built-in function in every version of Python 3, and the start argument has been available throughout. No import is required.
Frequently asked questions
What does enumerate() return?
(index, item) tuples — the running count first, the value from the iterable second. Unpack them with for i, x in enumerate(seq).How do I make enumerate() start at 1?
start argument: enumerate(seq, start=1). This shifts only the index count; the items and their order are unchanged.Why use enumerate() instead of range(len(...))?
enumerate() hands you the item already unpacked alongside its index, so it reads more clearly and avoids the off-by-one and re-indexing mistakes that range(len(seq)) plus seq[i] invites.