I l@ve RuBoard Previous Section Next Section

3.6 for Loops

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.

3.6.1 General Format

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.[5] 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.

[5] 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.

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'

3.6.2 Examples

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:[6]

[6] 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.

>>> 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.

Why You Will Care: File Scanner Loops

In general, loops come in handy any place you need to repeat or process something more than once. Since files contain multiple characters and lines, they are one of the more typical uses for loops. For example it's common to see file scanning loops coded with a while and breaks, instead of end-of-file tests at the top:

file = open("name", "r")
while 1:
    line = file.readline()     # fetch next line, if any
    if not line: break         # exit loop on end-of-file (empty string)
       Process line here

The for loop comes in handy for scanning files too; the readlines file method introduced in Chapter 2 hands you a lines list to step through:

file = open("name", "r")
for line in file.readlines():     # read into a lines list
    Process line here

In other cases, you might scan byte-by-byte (using while and file.read(1)), or load the file all at once (e.g., for char in file.read()). We'll learn more about file processing later in the book.

3.6.3 range and Counter Loops

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.[7]

[7] 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.

3.6.3.1 Examples

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


I l@ve RuBoard Previous Section Next Section