In this chapter, we meet Python’s two main
looping constructs—statements that repeat
an action over and over. The first of these, the
while
loop, provides a way to code general loops;
the second, the for
statement, is designed for
stepping through the items in a sequence object and running a block
of code for each item.
There are other kinds of looping operations in Python, but the two
statements covered here are the primary syntax provided for coding
repeated actions. We’ll also study a few unusual
statements such as break
and
continue
here, because they are used within loops.
Python’s
while
statement is its most general iteration
construct. In simple terms, it repeatedly executes a block of
indented statements, as long as a test at the top keeps evaluating to
a true value. When the test becomes false, control continues after
all the statements in the while
block; the body
never runs if the test is false to begin with.
The while
statement is one of two looping
statements (along with the for
). It is called a
loop because control keeps looping back to the start of the
statement, until the test becomes false. The net effect is that the
loop’s body is executed repeatedly while the test at
the top is true. Besides statements, Python also provides a handful
of tools that implicitly loop (iterate): the map
,
reduce
, and filter
functions;
the in
membership test; list comprehensions; and
more. We’ll explore most of these in Chapter 14.
In its most
complex form, the while
statement consists of a
header line with a test expression, a body of one or more indented
statements, and an optional else
part that is
executed if control exits the loop without running into a
break
statement. Python keeps evaluating the test
at the top, and executing the statements nested in the
while
part, until the test returns a false value:
while <test>: # Loop test <statements1> # Loop body else: # Optional else <statements2> # Run if didn't exit loop with break
To illustrate, here are a few of simple while
loops in action. The first just prints a message forever, by nesting
a print
statement in a while
loop. Recall that an integer 1 means true; since the test is always
true, Python keeps executing the body forever or until you stop its
execution. This sort of behavior is usually called an
infinite loop:
>>>while 1:
...print 'Type Ctrl-C to stop me!'
The next example keeps slicing off the first character of a string,
until the string is empty and hence false. It’s
typical to test an object directly like this, instead of using the
more verbose equivalent: while x != ''
:. Later in
this chapter, we’ll see other ways to step more
directly through the items in a string with a for
.
>>>x = 'spam'
>>>while x:
...print x,
...x = x[1:] # Strip first character off x.
... spam pam am m
The code below counts from the value of a
, up to
but not including b
. We’ll see an
easier way to do this with a Python for
and
range
later.
>>>a=0; b=10
>>>while a < b: # One way to code counter loops
...print a,
...a += 1 # Or, a = a+1
... 0 1 2 3 4 5 6 7 8 9
Now
that we’ve seen our first Python loop, we should
introduce two simple statements that have a purpose only when nested
inside loops—the
break
and
continue
statements. We will also study the loop
else
clause here because it is intertwined with
break
, and Python’s empty
placeholder statement, the pass
. In Python:
break
Jumps out of the closest enclosing loop (past the entire loop statement)
continue
Jumps to the top of the closest enclosing loop (to the loop’s header line)
pass
Does nothing at all: it’s an empty statement placeholder
else
blockRuns if and only if the loop is exited normally—without hitting
a break
Factoring in break
and continue
statements,
the
general format of the while
loop looks like this:
while <test1>: <statements1> if <test2>: break # Exit loop now, skip else. if <test3>: continue # Go to top of loop now. else: <statements2> # If we didn't hit a 'break'
break
and continue
statements
can appear anywhere inside the while
(and
for
) loop’s body, but they are
usually coded further nested in an if
test, to
take action in response to some sort of condition.
Let’s turn to a few simple examples to see how these
statements come together in practice. The
pass
statement
is used when the syntax requires a statement, but you have nothing
useful to say. It is often used to code an empty body for a compound
statement. For instance, if you want to code an infinite loop that
does nothing each time through, do it with a pass:
while 1: pass # Type Ctrl-C to stop me!
Since the body is just an empty statement, Python gets stuck in this
loop.[1]
pass
is roughly to
statements as
None
is to
objects—an explicit nothing. Notice that the
while
loop’s body is on the same
line as the header, after the colon; as in the if
,
this only works if the body isn’t a compound
statement.
The continue
statement is an immediate jump to the
top of a loop. It sometimes lets you avoid statement nesting; the
next example uses continue
to skip odd numbers.
This code prints all even numbers less than 10 and greater than or
equal to 0. Remember, 0 means false, and %
is the
remainder-of-division operator, so this loop counts down to zero,
skipping numbers that aren’t multiples of two (it
prints 8 6 4 2 0
):
x = 10 while x: x = x-1 # Or, x -= 1 if x % 2 != 0: continue # Odd?--skip print print x,
Because continue
jumps to the top of the loop, you
don’t need to nest the print
statement inside an if
test; the
print
is only reached if the
continue
is not run. If this sounds similar to a
“goto” in other languages it
should; Python has no goto statement, but because
continue
lets you jump about in a program, many of
the warnings about readability and maintainability you may have heard
about goto apply. continue
should probably be used
sparingly, especially when you’re first getting
started with Python; the example above, for instance, might be
clearer if the print
were nested under the
if
:
x = 10 while x: x = x-1 if x % 2 == 0: # Even?-- print print x,
The break
statement is an immediate loop exit.
Because code below it is never reached, the break
can also sometimes avoid nesting. For example, here is a simple
interactive loop, which inputs data with
raw_input
, and exits when the user enters
“stop” for the name request:
>>>while 1:
...name = raw_input('Enter name:')
...if name == 'stop': break
...age = raw_input('Enter age: ')
...print 'Hello', name, '=>', int(age) ** 2
... Enter name:mel
Enter age:40
Hello mel => 1600 Enter name:bob
Enter age:30
Hello bob => 900 Enter name:stop
Notice how this code converts the age
input to an
integer before raising it to the second power, with
int
; raw_input
returns user
input as a string. In Chapter 22,
you’ll see that it also raises an exception on
end-of-file (e.g., if users type Ctrl-Z or Ctrl-D); if it matters,
wrap raw_input
in try
statements.
When combined with the loop else
, the
break
statement can often eliminate the search
status flags used in other languages. For instance, the following
piece of code determines if a positive integer number
y
is prime by searching for factors greater than
1:
x = y / 2 # For some y > 1 while x > 1: if y % x == 0: # Remainder print y, 'has factor', x break # Skip else x = x-1 else: # Normal exit print y, 'is prime'
Rather than setting a flag to be tested when the loop is exited,
insert a break
where a factor is found. This way,
the loop else
can assume that it will be executed
only if no factor was found; if you don’t hit the
break
, the number is prime.[2]
The loop else
is also run if the body of the loop
is never executed, since you don’t run a
break
in that event either; in a
while
loop, this happens if the test in the header
is false to begin with. In the example above, you still get the
“is prime message” if
x
is initially less than or equal to 1 (e.g., if
y
is 2).
Because the loop else
clause is unique to Python,
it tends to perplex some newcomers on first glance. In more general
terms, the loop else
provides explicit syntax for
a common coding scenario—it is a coding structure that lets you
catch the “other” way out of a
loop, without setting and checking flags or conditions.
Suppose, for instance, that you are writing a loop to search a list for a value, and need to know whether the value was found after you exit the loop. You might code such a task this way:
found = 0 while x and not found: if match(x[0]): # Value at front? print 'Ni' found = 1 else: x = x[1:] # Slice off front and repeat. if not found: print 'not found'
Here, we initialize, set, and later test a flag, to know if the
search succeeded or not. This is valid Python code, and does work;
but it’s exactly the sort of structure that the loop
else
is there to handle. Here’s
an else
equivalent:
while x: # Exit when x empty. if match(x[0]): print 'Ni' break # Exit, go around else. x = x[1:] else: print 'Not found' # Only here if exhausted x.
Here, the flag is gone, and we replaced the if
test at loop end with an else
(lined up vertically
with the word while
, by indentation). Because the
break
inside the main part of the
while
exits the loop and goes around the
else
, this serves as a more structured way to
catch the search failure case.
Some readers might notice that the prior example’s
else could be replaced with a test for an empty x
after the loop (e.g., if not x
:). Although
that’s true in this example, the else provides
explicit syntax for this coding pattern (it’s more
obviously a search failure clause here), and such an explicit empty
test may not apply in some cases. Moreover, the loop else becomes
even more useful when used in conjunction with the
for
loop, because sequence iteration is not under
your control.
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.
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'
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.
The for
loop subsumes most
counter-style loops. It’s generally simpler to code
and quicker to run than a while
, so
it’s the first tool you should reach for whenever
you need to step through a sequence. But there are also situations
where you will need to iterate in a more specialized way. For
example, what if you need to visit every second or third item in a
list, or change the list along the way? How about traversing more
than one sequence in parallel, in the same for
loop?
You can always code such unique iterations with a
while
loop and manual indexing, but Python
provides two built-ins that allow you to specialize the iteration in
a for
:
The built-in range
function returns a list of
successively higher integers, which can be used as indexes in a
for
.[3]
The built-in zip
function returns a list a
parallel-item tuples, which can be used to traverse multiple
sequences in a for
.
Let’s look at each of these built-ins in turn.
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 integer in the result (steps default to one). Ranges
can also be nonpositive, and nonascending, if you want them to be:
>>>range(-5, 5)
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4] >>>range(5, -5, -1)
[5, 4, 3, 2, 1, 0, -1, -2, -3, -4]
Although such range results may be useful all by themselves, they
tend to come in most handy within for
loops. For
one thing, they provide a simple way to repeat an action a specific
number of times. To print three lines, for example, use a
range
to generate the appropriate number of
integers:
>>>for i in range(3):
...print i, 'Pythons'
... 0 Pythons 1 Pythons 2 Pythons
range
is also commonly used to iterate over a
sequence indirectly. The easiest and fastest way to step through a
sequence exhaustively is always 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
Notice the trailing comma on the print
statement
here, to suppress the default line feed (each print keeps adding to
the current output line). Internally, the for
handles the details of the iteration automatically. If you really
need to take over the indexing logic explicitly, you can do it with a
while
loop:
>>>i = 0
>>>while i < len(X): # while loop iteration
...print X[i],; i += 1
... s p a m
You can also do manual indexing with a for
, if
you use
range
to generate a list of indexes to iterate
through:
>>>X
'spam' >>>len(X) # Length of string
4 >>>range(len(X)) # All legal offsets into X
[0, 1, 2, 3] >>> >>>for i in range(len(X)): print X[i], # Manual for indexing
... s p a m
The example here is stepping over a list of
offsets into X
, not the
actual items of X
; we need to
index back into X
within the loop to fetch each
item.
The last example
of
the prior section works, but it probably runs more slowly than it has
to. Unless you have a special indexing requirement,
you’re always better off using the simple
for
loop form in Python—use
for
instead of while
whenever
possible, and don’t resort to
range
calls in for
loops except
as a last resort.
However, the same coding pattern used in that prior example also allows us to do more specialized sorts of traversals:
>>>S = 'abcdefghijk'
>>>range(0, len(S), 2)
[0, 2, 4, 6, 8, 10] >>>for i in range(0, len(S), 2): print S[i],
... a c e g i k
Here, we visit every second item in string
S
, by stepping over the generated
range
list. To visit every third item, change the
third range
argument to be 3, and so on. In
effect, range
used this way lets you skip items in
loops, while still retaining the simplicity of the
for
. See also Python 2.3’s new
optional third slice limit, in Section 5.2.2 in Chapter 5. In 2.3, a similar effect may be achieved
with:
for x in S[::2]: print x
Another common place you
may use range
and
for
combined is in loops that change a list as it
is being traversed. The following example needs an index to be able
to assign an updated value to each position as we go:
>>> L = [1, 2, 3, 4, 5] >>> >>> for i in range(len(L)): # Add one to each item in L ... L[i] += 1 # Or L[i] = L[i] + 1 ... >>> L [2, 3, 4, 5, 6]
There is no way to do the same with a simple for x in
L
: style loop here, because such a loop iterates through
actual items, not list positions. The equivalent
while
requires a bit more work on our
part:[4]
>>> i = 0 >>> while i < len(L): ... L[i] += 1 ... i += 1 ... >>> L [3, 4, 5, 6, 7]
The range
trick traverses sequences with
for
in nonexhaustive fashion. The built-in
zip
function allows us to use
for
loops to visit
multiple sequences in
parallel. In basic operation,
zip
takes one or more sequences, and returns a
list of tuples that pair up parallel items taken from its arguments.
For example, suppose we’re working with two lists:
>>>L1 = [1,2,3,4]
>>>L2 = [5,6,7,8]
To combine the items in these lists, we can use
zip
:
>>> zip(L1,L2)
[(1, 5), (2, 6), (3, 7), (4, 8)]
Such a result may be useful in other contexts. When wedded with the
for
loop, though, it supports parallel iterations:
>>>for (x,y) in zip(L1, L2):
...print x, y, '--', x+y
... 1 5 -- 6 2 6 -- 8 3 7 -- 10 4 8 -- 12
Here, we step over the result of the zip
call—the pairs of items pulled from the two lists. This
for
loop uses tuple assignment again to unpack
each tuple in the zip result (the first time through,
it’s as though we run
(x,y)=(1,5)
). The net effect is that we scan
both
L1
and
L2
in our loop. We could achieve a similar effect
with a while
loop that handles indexing manually,
but it would be more to type, and may be slower than the
for
/zip
approach.
The zip
function is more general than this example
suggests. For instance, it accepts any type of sequence, and more
than two arguments:
>>>T1, T2, T3 = (1,2,3), (4,5,6), (7,8,9)
>>>T3
(7, 8, 9) >>>zip(T1,T2,T3)
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
zip
truncates result tuples at the length of the
shortest sequence, when argument lengths differ:
>>>S1 = 'abc'
>>>S2 = 'xyz123'
>>> >>>zip(S1, S2)
[('a', 'x'), ('b', 'y'), ('c', 'z')]
The related, and older, built-in map
function
pairs items from sequences in a similar fashion, but pads shorter
sequences with None
if argument lengths differ:
>>> map(None, S1, S2)
[('a', 'x'), ('b', 'y'), ('c', 'z'), (None, '1'), (None, '2'), (None,'3')]
The example is actually using a degenerate form of the
map
built-in. Normally, map
takes a function, and one or more sequence arguments, and collects
the results of calling the function with parallel items taken from
the sequences. When the function argument is None
(as here), it simply pairs items like zip
.
map
and similar function-based tools are covered
in Chapter 11.
Dictionaries can always be created by coding a dictionary literal, or assigning to keys over time:
>>>D1 = {'spam':1, 'eggs':3, 'toast':5}
>>>D1
{'toast': 5, 'eggs': 3, 'spam': 1} >>>D1 = { }
>>>D1['spam'] = 1
>>>D1['eggs'] = 3
>>>D1['toast'] = 5
What to do, though, if your program obtains dictionary keys and values in lists at runtime, after you’ve coded your script?
>>>keys = ['spam', 'eggs', 'toast']
>>>vals = [1, 3, 5]
One solution to go from the lists to a dictionary is to
zip
the lists and step through them in parallel
with a for
loop:
>>>zip(keys, vals)
[('spam', 1), ('eggs', 3), ('toast', 5)] >>>D2 = { }
>>>for (k, v) in zip(keys, vals): D2[k] = v
... >>>D2
{'toast': 5, 'eggs': 3, 'spam': 1}
It turns out, though, that you can skip the for
loop altogether, and simply pass the zipped keys/values lists to the
built-in dict
constructor call in Python 2.2:
>>>keys = ['spam', 'eggs', 'toast']
>>>vals = [1, 3, 5]
>>>D3 = dict(zip(keys, vals))
>>>D3
{'toast': 5, 'eggs': 3, 'spam': 1}
The built-in name dict
is really a type name in
Python; calling it is something like a list-to-dictionary conversion,
but really is an object construction request (more about type names
in Chapter 23). Also, in Chapter 14, we’ll meet a related but
richer concept, the list comprehension, which
builds lists in a single expression.
[1] This code does nothing, forever. It probably
isn’t the most useful Python program ever written,
unless you want to test a CPU meter, or warm up your laptop computer
on a cold winter’s day. Frankly, though, we
couldn’t think of a better pass
example. We’ll see other places where it makes sense
later in the book (for instance, in Chapter 22, to
define empty classes that implement objects that behave like
“structs” and
“records” in other
languages).
[2] More
or less. Numbers less than 2 are not considered prime by the strict
mathematical definition. To be really picky, this code also fails for
negatives, fails for floating-point numbers, and will be broken by
the future /
“true” division change mentioned in
Chapter 4. If you want to experiment with this
code, be sure to see the exercise at the end of Part IV, which wraps
it in a function.
[3] 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 like
range
does. There’s no speed
advantage to xrange
, but it’s
useful as a space optimization if you have to generate a huge number
of values.
[4] A list comprehension
expression of the form [x+1 for x in L]
would do
similar work here as well, albeit without changing the original list
in-place (we could assign the expression’s new list
object result back to L
, but this would not update
any other references to the original list). See Chapter 14 for more on list comprehensions.