The for
loop is a generic sequence
iterator in Python: it can step through the items in any
object that responds to the sequence indexing operation. The
for
works on strings, lists, tuples, and new
objects we’ll create later with classes. We’ve already
seen the for
in action, when we mentioned the
iteration operation for sequence types in Chapter 2. Here, we’ll fill in the details we
skipped earlier.
The Python
for
loop begins with a header line that specifies
an assignment target (or targets), along with an object you want to
step through. The header is followed by a block of indented
statements, which you want to repeat:
for <target
> in <object
>: # assign object items to target <statements
> # repeated loop body: use target else: <statements
> # if we didn't hit a 'break'
When Python runs a for
loop, it assigns items in
the sequence object to the target, one by one,
and executes the loop body for each.[24] The loop
body typically uses the assignment target to refer to the current
item in the sequence, as though it were a cursor stepping through the
sequence. Technically, the for
works by repeatedly
indexing the sequence object on successively higher indexes (starting
at zero), until an index out-of-bounds exception is raised. Because
for
loops automatically manage sequence indexing
behind the scenes, they replace most of the
counter style loops you may be used to coding in
languages like C.
The
for
also supports
an optional else
block, which works exactly as it
does in while
loops; it’s executed if the
loop exits without running into a break
statement
(i.e., if all items in the sequence were visited). The
break
and continue
statements
we introduced above work the same in the for
loop
as they do in the while
too; we won’t repeat
their descriptions here, but the for
loop’s
complete format can be described this way:
for <target
> in <object
>: # assign object items to target <statements
> if <test
>: break # exit loop now, skip else if <test
>: continue # go to top of loop now else: <statements
> # if we didn't hit a 'break'
Let’s type a few for
loops
interactively. In the first example below, the name
x
is assigned to each of the three items in the
list in turn, from left to right, and the print
statement is executed for each. Inside the print
statement (the loop body), the name x
refers to
the current item in the list:
>>>for x in ["spam", "eggs", "ham"]:
... print x,
... spam eggs ham
The next two examples compute the sum and product of all the items in
a list. In Chapter 8, we’ll see built-ins
that apply operations like +
and
*
to items in a list, but it’s usually just
as easy to use a for
:
>>>sum = 0
>>>for x in [1, 2, 3, 4]:
...sum = sum + x
... >>>sum
10 >>>prod = 1
>>>for item in [1, 2, 3, 4]: prod = prod * item
... >>>prod
24
As mentioned, for
loops work on strings and tuples
too. One thing we haven’t mentioned is that, if you’re
iterating through a sequence of tuples, the loop target can actually
be a tuple of targets. This is just another case
of tuple unpacking assignment at work; remember,
the for
assigns items in the sequence to the
target, and assignment works the same everywhere:
>>>S, T = "lumberjack", ("and", "I'm", "okay")
>>>for x in S: print x,
... l u m b e r j a c k >>>for x in T: print x,
... and I'm okay >>>T = [(1, 2), (3, 4), (5, 6)]
>>>for (a, b) in T:
# tuple assignment at work... print a, b
... 1 2 3 4 5 6
Now, let’s look at something a bit more sophisticated. The next
example illustrates both the loop else
in a
for
and statement nesting. Given a list of objects
(items
) and a list of keys
(tests
), this code searches for each key in the
objects list, and reports on the search’s success:
>>>items = ["aaa", 111, (4, 5), 2.01]
# a set of objects >>>tests = [(4, 5), 3.14]
# keys to search for >>> >>>for key in tests:
# for all keys... for item in items:
# for all items... if item == key:
# check for match... print key, "was found"
... break
... else:
... print key, "not found!"
...
(4, 5) was found 3.14 not found!
Since the nested if
runs a
break
when a match is found, the loop
else
can assume that the search has failed. Notice
the nesting here: when this code runs, there are two loops going at
the same time. The outer loop scans the keys list, and the inner loop
scans the items list for each key. The nesting of the loop
else
is critical; it’s indented at the same
level as the header line of the inner for
loop, so
it’s associated with the inner loop (not the
if
or outer for
). By the way,
this example is easier to code if you employ the
in
operator from Chapter 2, to
test membership for us; since
in
implicitly scans a list looking for a match, it
replaces the inner loop:
>>>for key in tests:
# for all keys... if key in items:
# let Python check for a match... print key, "was found"
... else:
... print key, "not found!"
...
(4, 5) was found 3.14 not found!
In general, it’s a good idea to let Python do the work like
this. The next example performs a typical data-structure task with a
for
—collecting common items in two sequences
(strings). It’s roughly a simple set
intersection routine; after the loop runs,
res
refers to a list that contains all the items
found in both seq1
and
seq2
:[25]
>>>seq1 = "spam"
>>>seq2 = "scam"
>>> >>>res = []
# start empty >>>for x in seq1:
# scan first sequence... if x in seq2:
# common item?... res.append(x)
# add to result end...
>>>res
['s', 'a', 'm']
Unfortunately, this code is equipped to work only on two specific
variables: seq1
and seq2
. It
would be nice if this loop could be somehow generalized into a tool
we could use more than once. As we’ll see, that simple idea
leads us to functions, the topic of our
next
chapter.
The for
loop subsumes most counter-style loops, so
it’s the first tool you should reach for whenever you need to
step though a sequence. But there are also situations where you need
to iterate in a more specialized way. You can always code unique
iterations with a while
loop, but Python also
provides a way to specialize indexing in a for
;
the built-in range
function returns a list of
successively higher integers, which can be used as indexes in a
for
.[26]
A few examples will make this more concrete. The
range
function is really independent of
for
loops;
although it’s used most often to generate indexes in a
for
, you can use it anywhere you need a list of
integers:
>>> range(5), range(2, 5), range(0, 10, 2)
([0, 1, 2, 3, 4], [2, 3, 4], [0, 2, 4, 6, 8])
With one argument, range
generates a list with
integers from zero, up to but not including the argument’s
value. If you pass in two arguments, the first is taken as the
lower bound. An optional third argument can give
a step; if used, Python adds the step to each
successive node in the result (steps default to one). Now, the
easiest way to step through a sequence is with a simple
for
; Python handles most of the details for you:
>>>X = 'spam'
>>>for item in X: print item,
# simple iteration ... s p a m
Internally, the for
initializes an index, detects
the end of the sequence, indexes the sequence to fetch the current
item, and increments the index on each iteration. If you really need
to take over the indexing logic explicitly, you can do it with a
while
loop; this form is as close to a C
for
loop as you can come in Python:
>>>i = 0
>>>while i < len(X):
# while iteration ...print X[i],; i = i+1
... s p a m
And finally, you can still do manual indexing with a
for
, if you use range
to
generate a list of indexes to iterate through:
>>> for i in range(len(X)): print X[i],
# manual indexing
...
s p a m
But unless you have a special indexing requirement, you’re
always better off using the simple for
loop form
in Python. One situation where range
does come in
handy is for repeating an action a specific number of times; for
example, to print three lines, use a range
to
generate the appropriate number of integers:
>>> for i in range(3): print i, 'Pythons'
...
0 Pythons
1 Pythons
2 Pythons
[24] The name used as
the assignment target in a for
header line is
simply a (possibly new) variable in the namespace (scope) where the
for
statement is coded. There’s not much
special about it; it can even be changed inside the
for
loop’s body, but it’s
automatically set to the next item in the sequence when control
returns to the top of the loop again.
[25] This isn’t
exactly what some folks would call set intersection (an item can
appear more than once in the result if it appears more than once in
seq1
), but this isn’t exactly a text on set
theory either. To avoid duplicates, say if x in seq2 and x not in res
inside the loop instead. Incidentally, this is a
great example of how lists get built up dynamically (by program
code), rather than being written out as a constant. As we mentioned
before, most data structures are built, rather than written.
[26] Python also provides a
built-in called xrange
that generates indexes one
at a time instead of storing all of them in a list at once.
There’s no speed advantage to xrange
, but
it’s useful if you have to generate a huge number of
values.