enumerate()
Turn a plain iterable into an indexed one — without hand-managing a counter.
Common call
for i, x in enumerate(items):
Returns
iterator of (index, item) — not a list
Replaces
the manual `i = 0; ... i += 1` counter pattern
Watch out
lazy — wrap in list() to materialize
enumerate(iterableiterable — Any iterable — list, tuple, generator, string, dict (keys), file.type: iterable · required, startstart — First index value. Only affects the counter; the items are unchanged.type: int · default: 0=0)
→ enumerate
Demo
Live evaluation
Try:
Inputs
itemslistcomma-separated items
startintfirst index (empty = 0)
Output
enumerate(['apple', 'pear', 'plum'])
[[0, 'apple'], [1, 'pear'], [2, 'plum']]
enumerate returns an iterator — the demo materializes it as a list of (index, item) pairs so you can see the whole result. In real code you would iterate directly: `for i, x in enumerate(items):`. The start parameter only changes the counter; the items themselves are never modified.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| iterable | iterable | yes | Any iterable — list, tuple, generator, string, dict (keys), file. |
| start | int | no (0) | First index value. Only affects the counter; the items are unchanged. |
Return value
enumerate — An iterator of (index, item) tuples. Lazy — nothing is computed until you iterate.
Common patterns
Indexed loop with unpacking
The idiomatic replacement for manual counters.
for i, item in enumerate(items): print(i, item)
One-based numbering
Human-readable lists start at 1, not 0.
for i, line in enumerate(lines, start=1): print(f"{i}. {line}")
Item → position map
Comprehension over enumerate builds a lookup table in one pass.
positions = {item: i for i, item in enumerate(items)}
Examples
1. Basic indexing
list(enumerate(["a", "b", "c"]))
Returns
[(0, "a"), (1, "b"), (2, "c")]2. Custom start
list(enumerate(["a", "b"], start=10))
Returns
[(10, "a"), (11, "b")]3. Over a string
list(enumerate("abc"))
Returns
[(0, "a"), (1, "b"), (2, "c")]4. Empty is empty
list(enumerate([]))
Returns
[]Pitfalls
1. Iterator exhausts after one pass
enumerate returns an iterator, not a list. Loop through it twice and the second loop sees nothing.
Empty on reuse
e = enumerate(items) list(e) # [(0, "a"), (1, "b")] list(e) # []
second list() is empty
Materialize once
pairs = list(enumerate(items)) # reuse pairs freely
reusable list
2. start does not skip items
start changes the counter, not the input. All items still appear.
Misuse
list(enumerate(["a","b","c"], start=2))
[(2, "a"), (3, "b"), (4, "c")]
Actually skip
list(enumerate(["a","b","c"][2:]))
[(0, "c")]
3. Forgetting to unpack the pair
Without unpacking, the loop variable is the whole tuple.
Tuple leak
for x in enumerate(items): print(x)
(0, "a"), (1, "b"), ...
Unpack
for i, x in enumerate(items): print(i, x)
0 a, 1 b, ...
When to use
Use it
- Anywhere you need both the item and its index
- One-based numbering for humans (start=1)
- Building position lookup tables
- Iterables without len() — generators, files
Reach for something else
- Just the items → iterate directly
- Just indices → range(len(items))
- Parallel iteration over multiple iterables → zip
Notes
Complexity
O(1) per step
Return
enumerate object (iterator), not list
CPython impl
Python/bltinmodule.c :: enum_next — a tiny generator over the source iterator
Memory
O(1) — one running counter, no buffering
Thread-safe
The counter is safe; the source iterator is only as safe as its type
FAQ
It works, but you then have to index items[i] every step. enumerate gives you both at once, and works on any iterable — including ones without a len (generators, files, network streams).
History
2.3
enumerate() introduced.
2.6
start keyword argument added.