Python’s enumerate() Function Demystified
How and why you should use the built-in enumerate function in Python to write cleaner and more Pythonic loops.
Python’s enumerate
function is a mythical beast—it’s hard to summarize its purpose and usefulness in a single sentence.
And yet, it’s a super useful feature that many beginners and even intermediate Pythonistas are blissfully unaware of. Basically, enumerate()
allows you to loop over a collection of items while keeping track of the current item’s index in a counter variable.
Let’s take a look at an example:
names = ['Bob', 'Alice', 'Guido'] for index, value in enumerate(names): print(f'{index}: {value}')
This leads to the following output:
0: Bob 1: Alice 2: Guido
As you can see, this iterated over the names
list and generated an index for each element by increasing a counter variable starting at zero.
[ If you’re wondering about the f'...'
string syntax I used in the above example, this is a new string formatting technique available in Python 3.6 and above. ]
Make Your Loops More Pythonic With enumerate()
Now why is keeping a running index with the enumerate
function useful?
I noticed that new Python developers coming from a C or Java background sometimes use the following range(len(...))
antipattern to keep a running index while iterating over a list with a for
-loop:
# HARMFUL: Don't do this for i in range(len(my_items)): print(i, my_items[i])
By using the enumerate
function skillfully, like I showed you in the “names” example above, you can make this looping construct much more “Pythonic” and idiomatic.
There’s usually no need to generate element indexes manually in Python—you simply leave all of this work to the enumerate
function. And as a result your code will be easier to read and less vulnerable to typos.
Changing the Starting Index
Another useful feature is the ability to choose the starting index for the enumeration. The enumerate()
function accepts an optional argument which allows you to set the initial value for its counter variable:
names = ['Bob', 'Alice', 'Guido'] for index, value in enumerate(names, 1): print(f'{index}: {value}')
In the above example I changed the function call to enumerate(names, 1)
and the extra 1
argument now starts the index at one instead of zero:
1: Bob 2: Alice 3: Guido
Voilà, this is how you switch from zero-based indexing to starting with index 1 (or any other int
, for that matter) using Python’s enumerate()
function.
How enumerate()
Works Behind The Scenes
You might be wondering how the enumerate
function works behind the scenes. Part of it’s magic lies in the fact that enumerate
is implemented as a Python iterator. This means that element indexes are generated lazily (one by one, just-in-time), which keeps memory use low and keeps this construct so fast.
Let’s play with some more code to demonstrate what I mean:
>>> names = ['Bob', 'Alice', 'Guido'] >>> enumerate(names) <enumerate object at 0x1057f4120>
In the above code snippet I set up the same enumeration you’ve already seen in the previous examples. But instead of immediately looping over the result of the enumerate
call I’m just displaying the returned object on the Python console.
As you can see, it’s an “enumerate object.” This is the actual iterator. And like I said, it generates its output elements lazily and one by one when they’re requested.
In order to retrieve those “on demand” elements so we can inspect them, I’m going to call the built-in list()
function on the iterator:
>>> list(enumerate(names)) [(0, 'Bob'), (1, 'Alice'), (2, 'Guido')]
For each element in the input list (names
) the iterator returned by enumerate()
produces a tuple of the form (index, element)
. In your typical for-in loop you’ll use this to your advantage by leveraging Python’s data structure unpacking feature:
for index, element in enumerate(iterable): # ...
The enumerate
Function in Python – Key Takeaways
enumerate
is a built-in function of Python. You use it to loop over an iterable with an automatic running index generated by a counter variable.- The counter starts at 0 by default, but you can set it to any integer.
enumerate
was added to Python starting at version 2.3 with the implementation of PEP 279.- Python’s
enumerate
function helps you write more Pythonic and idiomatic looping constructs that avoid the use of clunky and error-prone manual indexing. - To use
enumerate
to its fullest potential, be sure to study up on Python’s iterators and data structure unpacking features.