DekGenius.com
[ Team LiB ] Previous Section Next Section

10.3 for Loops

The for loop is a generic sequence iterator in Python: it can step through the items in any ordered sequence object. The for works on strings, lists, tuples, and new objects we'll create later with classes.

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

The name used as the assignment target in a for header line is usually a (possibly new) variable in the scope where the for statement is coded. There's not much special about it; it can even be changed inside the loop's body, but will be automatically set to the next item in the sequence when control returns to the top of the loop again. After the loop, this variable normally still refers to the last item visited, which is the last item in the sequence unless the loop exits with a break statement.

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). In fact, the break and continue statements introduced above work the same in the for loop as they do in the while. 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'

10.3.2 Examples

Let's type a few for loops interactively. In the first example, 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 the next chapter, we'll see built-ins that apply operations like + and * to items in a list automatically, 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 *= item
...
>>> prod
24

For loops work on strings and tuples too—any sequence works in a for:

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

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:

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

Here, the first time through the loop, it's like writing: (a,b) = (1,2); the second time (a,b) is assigned (3,4), and so on. This isn't a special case; any assignment target works syntactically after the word for.

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 outcome:

>>> 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 we employ the in operator to test membership. 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 as much of the work as possible, for the sake of both brevity and performance. 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:

>>> 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 you could use more than once. As you'll see, that simple idea leads us to functions, the topic of Part IV.

Why You Will Care: File Scanners

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. To load a file's contents into a string all at once, you simply call read:

file = open('test.txt', 'r')
print file.read(  )

But in order to load a file in pieces, it's common to code either a while loop with breaks on end-of-file, or a for. To read by characters:

file = open('test.txt')
while 1:
    char = file.read(1)          # Read by character.
    if not char: break
    print char,

for char in open('test.txt').read(  ):
    print char

The for here also processes each character, but loads the file into memory all at once. To read by lines or blocks with a while loop:

file = open('test.txt')
while 1:
    line = file.readline(  )       # Read line by line.
    if not line: break
    print line,

file = open('test.txt', 'rb')
while 1:
    chunk = file.read(10)        # Read byte chucks.
    if not chunk: break
    print chunk,

To read text files line by line, though, the for loop tends to be easiest to code, and quickest to run:

for line in open('test.txt').readlines(  ): print line
for line in open('test.txt').xreadlines(  ):print line
for line in open('test.txt'):                print line

readlines loads a file all at once into a line-string list; xreadlines instead loads lines on demand, to avoid filling memory for large files; and the last example here relies on new file iterators, to achieve the equivalent of xreadlines (iterators will be covered in Chapter 14). The name open in all of the above can also be replaced with name file as of Python 2.2. See the library manual for more on the calls used here. As a general rule of thumb, the larger the size of data you read on each step, the quicker your program will run.


    [ Team LiB ] Previous Section Next Section