Reference

Reference · Loops

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.

XCODXReference · Updated

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

ParameterRequiredDefaultDescription
iterableYesAny 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.
startNo0The 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 (default 0) 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) pairsjust the index
Item accessalready unpackedseq[i] — extra indexing
Readabilityclear intentnoisier, error-prone
Use whenyou need index and valueyou 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?
A lazy enumerate object that yields (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?
Pass the 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.
Can I use enumerate() on a string or generator?
Yes — any iterable works, including strings, files and generators. It is consumed lazily, so it streams through large or infinite iterables without loading them into memory.