home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Previous Section Next Section

4.9 Control Flow Statements

A program's control flow is the order in which the program's code executes. The control flow of a Python program is regulated by conditional statements, loops, and function calls. This section covers the if statement and for and while loops; functions are covered later in this chapter. Raising and handling exceptions also affects control flow; exceptions are covered in Chapter 6.

4.9.1 The if Statement

Often, you need to execute some statements only if some condition holds, or choose statements to execute depending on several mutually exclusive conditions. The Python compound statement if, which uses if, elif, and else clauses, lets you conditionally execute blocks of statements. Here's the syntax for the if statement:

if expression:
    statement(s)
elif expression:
    statement(s)
elif expression:
    statement(s)
...
else expression:
    statement(s)

The elif and else clauses are optional. Note that unlike some languages, Python does not have a switch statement, so you must use if, elif, and else for all conditional processing.

Here's a typical if statement:

if x < 0: print "x is negative"
elif x % 2: print "x is positive and odd"
else: print "x is even and non-negative"

When there are multiple statements in a clause (i.e., the clause controls a block of statements), the statements are placed on separate logical lines after the line containing the clause's keyword (known as the header line of the clause) and indented rightward from the header line. The block terminates when the indentation returns to that of the clause header (or further left from there). When there is just a single simple statement, as here, it can follow the : on the same logical line as the header, but it can also be placed on a separate logical line, immediately after the header line and indented rightward from it. Many Python practitioners consider the separate-line style more readable:

if x < 0:
    print "x is negative"
elif x % 2:
    print "x is positive and odd"
else:
    print "x is even and non-negative"

You can use any Python expression as the condition in an if or elif clause. When you use an expression this way, you are using it in a Boolean context. In a Boolean context, any value is taken as either true or false. As we discussed earlier, any non-zero number or non-empty string, tuple, list, or dictionary evaluates as true. Zero (of any numeric type), None, and empty strings, tuples, lists, and dictionaries evaluate as false. When you want to test a value x in a Boolean context, use the following coding style:

if x:

This is the clearest and most Pythonic form. Don't use:

if x is True:
if x =  = True:
if bool(x):

There is a crucial difference between saying that an expression "returns True" (meaning the expression returns the value 1 intended as a Boolean result) and saying that an expression "evaluates as true" (meaning the expression returns any result that is true in a Boolean context). When testing an expression, you care about the latter condition, not the former.

If the expression for the if clause evaluates as true, the statements following the if clause execute, and the entire if statement ends. Otherwise, the expressions for any elif clauses are evaluated in order. The statements following the first elif clause whose condition is true, if any, are executed, and the entire if statement ends. Otherwise, if an else clause exists, the statements following it are executed.

4.9.2 The while Statement

The while statement in Python supports repeated execution of a statement or block of statements that is controlled by a conditional expression. Here's the syntax for the while statement:

while expression:
    statement(s)

A while statement can also include an else clause and break and continue statements, as we'll discuss shortly.

Here's a typical while statement:

count = 0
while x > 0:
    x = x // 2            # truncating division
    count += 1
print "The approximate log2 is", count

First, expression, which is known as the loop condition, is evaluated. If the condition is false, the while statement ends. If the loop condition is satisfied, the statement or statements that comprise the loop body are executed. When the loop body finishes executing, the loop condition is evaluated again, to see if another iteration should be performed. This process continues until the loop condition is false, at which point the while statement ends.

The loop body should contain code that eventually makes the loop condition false, or the loop will never end unless an exception is raised or the loop body executes a break statement. A loop that is in a function's body also ends if a return statement executes in the loop body, as the whole function ends in this case.

4.9.3 The for Statement

The for statement in Python supports repeated execution of a statement or block of statements that is controlled by an iterable expression. Here's the syntax for the for statement:

for target in iterable:
    statement(s)

Note that the in keyword is part of the syntax of the for statement and is functionally unrelated to the in operator used for membership testing. A for statement can also include an else clause and break and continue statements, as we'll discuss shortly.

Here's a typical for statement:

for letter in "ciao":
    print "give me a", letter, "..."

iterable may be any Python expression suitable as an argument to built-in function iter, which returns an iterator object (explained in detail in the next section). target is normally an identifier that names the control variable of the loop; the for statement successively rebinds this variable to each item of the iterator, in order. The statement or statements that comprise the loop body execute once for each item in iterable (unless the loop ends because an exception is raised or a break or return statement is executed).

A target with multiple identifiers is also allowed, as with an unpacking assignment. In this case, the iterator's items must then be sequences, each with the same length, equal to the number of identifiers in the target. For example, when d is a dictionary, this is a typical way to loop on the items in d:

for key, value in d.items(  ):
    if not key or not value: del d[key]    # keep only true keys and values

The items method returns a list of key/value pairs, so we can use a for loop with two identifiers in the target to unpack each item into key and value.

If the iterator has a mutable underlying object, that object must not be altered while a for loop is in progress on it. For example, the previous example cannot use iteritems instead of items. iteritems returns an iterator whose underlying object is d, so therefore the loop body cannot mutate d (by del d[key]). items returns a list, though, so d is not the underlying object of the iterator and the loop body can mutate d.

The control variable may be rebound in the loop body, but is rebound again to the next item in the iterator at the next iteration of the loop. The loop body does not execute at all if the iterator yields no items. In this case, the control variable is not bound or rebound in any way by the for statement. If the iterator yields at least one item, however, when the loop statement terminates, the control variable remains bound to the last value to which the loop statement has bound it. The following code is thus correct, as long as someseq is not empty:

for x in someseq:
    process(x)
print "Last item processed was", x
4.9.3.1 Iterators

An iterator is any object i such that you can call i.next( ) without any arguments. i.next( ) returns the next item of iterator i, or, when iterator i has no more items, raises a StopIteration exception. When you write a class (see Chapter 5), you can allow instances of the class to be iterators by defining such a method next. Most iterators are built by implicit or explicit calls to built-in function iter, covered in Chapter 8. Calling a generator also returns an iterator, as we'll discuss later in this chapter.

The for statement implicitly calls iter to get an iterator. The following statement:

for x in c: 
    statement(s)

is equivalent to:

_temporary_iterator = iter(c)
while True:
    try: x = _temporary_iterator.next(  )
    except StopIteration: break
    statement(s)

Thus, if iter(c) returns an iterator i such that i.next( ) never raises StopIteration (an infinite iterator), the loop for x in c: never terminates (unless the statements in the loop body contain suitable break or return statements or propagate exceptions). iter(c), in turn, calls special method c._ _iter_ _( ) to obtain and return an iterator on c. We'll talk more about the special method _ _iter_ _ in Chapter 5.

Iterators were first introduced in Python 2.2. In earlier versions, for x in S: required S to be a sequence that was indexable with progressively larger indices 0, 1, ..., and raised an IndexError when indexed with a too-large index. Thanks to iterators, the for statement can now be used on a container that is not a sequence, such as a dictionary, as long as the container is iterable (i.e., it defines an _ _iter_ _ special method so that function iter can accept the container as the argument and return an iterator on the container). Built-in functions that used to require a sequence argument now also accept any iterable.

4.9.3.2 range and xrange

Looping over a sequence of integers is a common task, so Python provides built-in functions range and xrange to generate and return integer sequences. The simplest, most idiomatic way to loop n times in Python is:

for i in xrange(n):
    statement(s)

range(x) returns a list whose items are consecutive integers from 0 (included) up to x (excluded). range(x,y) returns a list whose items are consecutive integers from x (included) up to y (excluded). The result is the empty list if x is greater than or equal to y. range(x,y,step) returns a list of integers from x (included) up to y (excluded), such that the difference between each two adjacent items in the list is step. If step is less than 0, range counts down from x to y. range returns the empty list when x is greater than or equal to y and step is greater than 0, or when x is less than or equal to y and step is less than 0. If step equals 0, range raises an exception.

While range returns a normal list object, usable for all purposes, xrange returns a special-purpose object, specifically intended to be used in iterations like the for statement shown previously. xrange consumes less memory than range for this specific use. Leaving aside memory consumption, you can use range wherever you could use xrange.

4.9.3.3 List comprehensions

A common use of a for loop is to inspect each item in a sequence and build a new list by appending the results of an expression computed on some or all of the items inspected. The expression form, called a list comprehension, lets you code this common idiom concisely and directly. Since a list comprehension is an expression (rather than a block of statements), you can use it directly wherever you need an expression (e.g., as an actual argument in a function call, in a return statement, or as a subexpression for some other expression).

A list comprehension has the following syntax:

[ expression for target in iterable lc-clauses ]

target and iterable are the same as in a regular for statement. You must enclose the expression in parentheses if it indicates a tuple.

lc-clauses is a series of zero or more clauses, each with one of the following forms:

for target in iterable
if expression

target and iterable in each for clause of a list comprehension have the same syntax as those in a regular for statement, and the expression in each if clause of a list comprehension has the same syntax as the expression in a regular if statement.

A list comprehension is equivalent to a for loop that builds the same list by repeated calls to the resulting list's append method. For example (assigning the list comprehension result to a variable for clarity):

result1 = [x+1 for x in some_sequence]

is the same as the for loop:

result2 = [  ]
for x in some_sequence:
    result2.append(x+1)

Here's a list comprehension that uses an if clause:

result3 = [x+1 for x in some_sequence if x>23]

which is the same as a for loop that contains an if statement:

result4 = [  ]
for x in some_sequence:
    if x>23:
        result4.append(x+1)

And here's a list comprehension that uses a for clause:

result5 = [x+y for x in alist for y in another]

which is the same as a for loop with another for loop nested inside:

result6 = [  ]
for x in alist:
    for y in another:
        result6.append(x+y)

As these examples show, the order of for and if in a list comprehension is the same as in the equivalent loop, but in the list comprehension the nesting stays implicit.

4.9.4 The break Statement

The break statement is allowed only inside a loop body. When break executes, the loop terminates. If a loop is nested inside other loops, break terminates only the innermost nested loop. In practical use, a break statement is usually inside some clause of an if statement in the loop body so that it executes conditionally.

One common use of break is in the implementation of a loop that decides if it should keep looping only in the middle of each loop iteration:

while True:                     # this loop can never terminate naturally
    x = get_next(  )
    y = preprocess(x)
    if not keep_looping(x, y): break
    process(x, y)

4.9.5 The continue Statement

The continue statement is allowed only inside a loop body. When continue executes, the current iteration of the loop body terminates, and execution continues with the next iteration of the loop. In practical use, a continue statement is usually inside some clause of an if statement in the loop body so that it executes conditionally.

The continue statement can be used in place of deeply nested if statements within a loop. For example:

for x in some_container:
    if not seems_ok(x): continue
    lowbound, highbound = bounds_to_test(  )
    if x<lowbound or x>=highbound: continue
    if final_check(x):
        do_processing(x)

This equivalent code does conditional processing without continue:

for x in some_container:
    if seems_ok(x):
        lowbound, highbound = bounds_to_test(  )
        if lowbound<=x<highbound:
            if final_check(x):
                do_processing(x)

Both versions function identically, so which one you use is a matter of personal preference.

4.9.6 The else Clause on Loop Statements

Both the while and for statements may optionally have a trailing else clause. The statement or statements after the else execute when the loop terminates naturally (at the end of the for iterator or when the while loop condition becomes false), but not when the loop terminates prematurely (via break, return, or an exception). When a loop contains one or more break statements, you often need to check whether the loop terminates naturally or prematurely. You can use an else clause on the loop for this purpose:

for x in some_container:
    if is_ok(x): break             # item x is satisfactory, terminate loop
else:
    print "Warning: no satisfactory item was found in container"
    x = None

4.9.7 The pass Statement

The body of a Python compound statement cannot be empty—it must contain at least one statement. The pass statement, which performs no action, can be used as a placeholder when a statement is syntactically required but you have nothing specific to do. Here's an example of using pass in a conditional statement as a part of somewhat convoluted logic, with mutually exclusive conditions being tested:

if condition1(x):
    process1(x)
elif x>23 or condition2(x) and x<5:
    pass                                # nothing to be done in this case
elif condition3(x):
    process3(x)
else:
    process_default(x)

4.9.8 The try Statement

Python supports exception handling with the try statement, which includes try, except, finally, and else clauses. A program can explicitly raise an exception with the raise statement. As we'll discuss in detail in Chapter 6, when an exception is raised, normal control flow of the program stops and Python looks for a suitable exception handler.

    Previous Section Next Section