Sometimes you have to iterate over a collection and count the steps you’ve taken. For example, let’s write a really simple function that returns the index of the leftmost occurrence of a given character in the given string.
def indexof(str, char):
i = 0
for c in str:
if c == char:
return i
i += 1
return -1
Or, we could write it as:
def indexof(str, char):
for i in range(len(str)):
if str[i] == char:
return i
return -1
The second one looks a little bit better. Still, I wish we could write the loop
so that the for statement (i.e. the first line of the loop) expresses
all aspects of the iteration. In other words, if we are both stepping over the
string and incrementing a counter, it is best if they
happen simultaneously each time we step through the loop.
Turns out it’s not uncommon to need a counter variable while iterating over the
elements of some collection. So Python has a builtin function specifically for
this purpose: enumerate (new in Python 2.3). At each iteration
it returns a 2-tuple of (counter, object). So our indexof
becomes:
def indexof(str, char):
for index, curchar in enumerate(str):
if curchar == char:
return index
return -1
Now we don’t have to clumsily
declare a counter variable and increment it manually. Our final
implementation also works with generators and unindexable
collections that we cannot subscript (i.e. do
collection[index]).