Chapter 9. if Tests

This chapter presents the Python if statement—the main statement used for selecting from alternative actions based on test results. Because this is our first exposure to compound statements—statements which embed other statements—we will also explore the general concepts behind the Python statement syntax model here. And because the if statement introduces the notion of tests, we’ll also use this chapter to study the concepts of truth tests and Boolean expressions in general.

if Statements

In simple terms, the Python if statement selects actions to perform. It’s the primary selection tool in Python and represents much of the logic a Python program possesses. It’s also our first compound statement; like all compound Python statements, the if may contain other statements, including other ifs. In fact, Python lets you combine statements in a program both sequentially (so that they execute one after another), and arbitrarily nested (so that they execute only under certain conditions).

General Format

The Python if statement is typical of most procedural languages. It takes the form of an if test, followed by one or more optional elif tests (meaning “else if”), and ends with an optional else block. Each test and the else have an associated block of nested statements indented under a header line. When the statement runs, Python executes the block of code associated with the first test that evaluates to true, or the else block if all tests prove false. The general form of an if looks like this:

if <test1>:               # if test 
    <statements1>         # Associated block
elif <test2>:             # Optional elifs 
    <statements2>
else:                     # Optional else
    <statements3>

Examples

Let’s look at a few simple examples of the if statement at work. All parts are optional except the initial if test and its associated statements; in the simplest case, the other parts are omitted:

>>> if 1:
...     print 'true'
...
true

Notice how the prompt changes to " . . . " for continuation lines in the basic interface used here (in IDLE, you’ll simply drop down to an indented line instead—hit Backspace to back up); a blank line terminates and runs the entire statement. Remember that 1 is Boolean true, so this statement’s test always succeeds; to handle a false result, code the else:

                  >>> if not 1:
                  ...     print 'true'
                  ... else:
                  ...     print 'false'
                  ...
                  false

Now, here’s an example of the most complex kind of if statement—with all its optional parts present:

>>> x = 'killer rabbit'
>>> if x == 'roger':
...     print "how's jessica?"
... elif x == 'bugs':
...     print "what's up doc?"
... else:
...     print 'Run away! Run away!'
...
Run away! Run away!

This multiline statement extends from the if line, through the else block. When run, Python executes the statements nested under the first test that is true, or the else part if all tests are false (in this example, they are). In practice, both the elif and else parts may be omitted, and there may be more than one statement nested in each section. Moreover, the words if, elif, and else are associated by the fact that they line up vertically, with the same indentation.

Multiway branching

If you’ve used languages like C or Pascal, you might be interested to know that there is no “switch” or “case” statement in Python that selects an action based on a variable’s value. Instead, multiway branching is coded as either a series of if/elif tests as done in the prior example, or by indexing dictionaries or searching lists. Since dictionaries and lists can be built at runtime, they’re sometimes more flexible than hardcoded if logic:

>>> choice = 'ham'
>>> print {'spam':  1.25,         # A dictionary-based 'switch'
...        'ham':   1.99,         # Use has_key(  ) or get(  ) for default.
...        'eggs':  0.99,
...        'bacon': 1.10}[choice]
1.99

Although it usually takes a few moments for this to sink in the first time you see it, this dictionary is a multiway branch—indexing on key choice branches to one of a set of values much like a “switch” in C. An almost equivalent and more verbose Python if statement might look like this:

>>> if choice == 'spam':
...     print 1.25
... elif choice == 'ham':
...     print 1.99
... elif choice == 'eggs':
...     print 0.99
... elif choice == 'bacon':
...     print 1.10
... else:
...     print 'Bad choice'
...
1.99

Notice the else clause on the if here to handle the default case when no key matches. As we saw in Chapter 6, dictionary defaults can be coded with has_key tests, get method calls, or exception catching. All of the same techniques can be used here to code a default action in a dictionary-based multiway branch. Here’s the get scheme at work with defaults:

>>> branch = {'spam': 1.25,
...           'ham':  1.99,
...           'eggs': 0.99}

>>> print branch.get('spam', 'Bad choice')
1.25
>>> print branch.get('bacon', 'Bad choice')
Bad choice

Dictionaries are good at associating values with keys, but what about more complicated actions you can code in if statements? In Part IV, you’ll learn that dictionaries can also contain functions to represent more complex branch actions, and implement general jump tables. Such functions appear as dictionary values, are often coded as lambdas, and are called by adding parenthesis to trigger their action.

Python Syntax Rules

In general, Python has a simple, statement-based syntax. But there are a few properties you need to know:

  • Statements execute one after another, until you say otherwise. Python normally runs statements in a file or nested block from first to last, but statements like the if (and, as you’ll see, loops) cause the interpreter to jump around in your code. Because Python’s path through a program is called the control flow, things like the if that affect it are called control-flow statements.

  • Block and statement boundaries are detected automatically. There are no braces or “begin/end” delimiters around blocks of code; instead, Python uses the indentation of statements under a header to group the statements in a nested block. Similarly, Python statements are not normally terminated with a semicolon; rather, the end of a line usually marks the end of the statements coded on that line.

  • Compound statements = header, ":“, indented statements. All compound statements in Python follow the same pattern: a header line terminated with a colon, followed by one or more nested statements usually indented under the header. The indented statements are called a block (or sometimes, a suite). In the if statement, the elif and else clauses are part of the if, but are header lines with nested blocks of their own.

  • Blank lines, s paces, and comments are usually ignored. Blank lines are ignored in files (but not at the interactive prompt). Spaces inside statements and expressions are almost always ignored (except in string literals and indentation). Comments are always ignored: they start with a # character (not inside a string literal) and extend to the end of the current line.

  • Docstrings are ignored but saved, and displayed by tools. Python supports an additional comment form called documentation strings (docstrings for short), which, unlike # comments, are retained. Docstrings are simply strings that show up at the top of program files and some statements, and are automatically associated with objects. Their contents are ignored by Python, but they are automatically attached to objects at runtime, and may be displayed with documentation tools. Docstrings are part of Python’s larger documentation and are covered at the end of Part III.

As you’ve seen, there are no variable type declarations in Python; this fact alone makes for a much simpler language syntax than what you may be used to. But for most new users, the lack of braces and semicolons to mark blocks and statements seems to be the most novel syntactic feature of Python, so let’s explore what this means in more detail here.

Block Delimiters

Python detects block boundaries automatically, by line indentation— the empty space to the left of your code. All statements indented the same distance to the right belong to the same block of code. In other words, the statements within a block line up vertically. The block ends at a line less indented or the end of the file, and more deeply nested blocks are simply indented further to the right than the statements in the enclosing block.

For instance, Figure 9-1 demonstrates the block structure of the following code:

x = 1
if x:
    y = 2
    if y:
        print 'block2'
    print 'block1'
print 'block0'
Nested code blocks
Figure 9-1. Nested code blocks

This code contains three blocks: the first (the top-level of the file) is not indented at all; the second (within the outer if statement) is indented four spaces; and the third (the print statement under the nested if) is indented eight spaces.

In general, top-level (unnested) code must start in column 1. Nested blocks can start in any column; indentation may consist of any number of spaces and tabs, as long as it’s the same for all the statements in a given block. That is, Python doesn’t care how you indent your code; it only cares that it’s done consistently. Technically, tabs count for enough spaces to move the current column number up to a multiple of 8, but it’s usually not a good idea to mix tabs and spaces within a block—use one or the other.

Indentation to the left of your code is the only major place in Python where whitespace matters; in most other contexts, space can be coded or not. However, indentation is really part of Python syntax, not just a stylistic suggestion: all the statements within any given single block must be indented the same, or Python reports a syntax error. This is on purpose—because you don’t need to explicitly mark the start and end of a nested block of code, it removes some of the syntactic clutter found in other languages.

This syntax model also enforces indentation consistency, a crucial component of readability in structured programming languages like Python. Python’s syntax is sometimes called the “what you see is what you get” of languages—the indentation of code unambiguously tells readers what it is associated with. Python’s consistent appearance makes code easier to maintain.

Consistently-indented code always satisfies Python’s rules. Moreover, most text editors (including IDLE) make it easy to follow Python’s indentation model, by automatically indenting code as you type it.

Statement Delimiters

Statements normally end at the end of the line they appear on. This covers the vast majority of the Python statements you’ll code. When statements are too long to fit on a single line, though, a few special rules may be used to make them span multiple continuation lines:

  • Statements may span lines if you’re continuing an open syntactic pair. For statements that are too long to fit on one line, Python lets you continue typing the statement on the next line, if you’re coding something enclosed in ( ), { }, or [ ] pairs. For instance, expressions in parenthesis and dictionary and list literals can span any number of lines; your statement doesn’t end until the line on which you type the closing part of the pair ( ), }, or ]). Continuation lines can start at any indentation level.

  • Statements may span lines if they end in a backslash. This is a somewhat outdated feature, but if a statement needs to span multiple lines, you can also add a backslash () at the end of the prior line to indicate you’re continuing on the next line. But since you can also continue by adding parentheses around long constructs, backslashes are almost never needed.

  • Other rules. Very long string literals can span lines arbitrarily. In fact, the triple-quoted string blocks we met in Chapter 5 are designed to do so. Although uncommon, you can also terminate statements with a semicolon—this is sometimes used to squeeze more than one simple statement on a single line. Finally, comments and blank lines can appear anywhere.

A Few Special Cases

Here’s what a continuation line looks like, using the open pairs rule; we can span delimited constructs across any number of lines:

L = ["Good", 
     "Bad", 
     "Ugly"]                    # Open pairs may span lines.

This works for anything in parentheses too: expressions, function arguments, functions headers (see Chapter 12), and so on. If you like using backslashes to continue you can, but it’s not usually necessary:

if a == b and c == d and   
   d == e and f == g:
   print 'olde'                  # Backslashes allow continuations.

Because any expression can be enclosed in parenthesis, you can usually simply wrap something in parenthesis anytime you need to span multiple lines:

if (a == b and c == d and
    d == e and e == f):
    print 'new'                  # But parentheses usually do too.

As a special case, Python allows you to write more than one non-compound statement (i.e., statements without nested statements) on the same line, separated by semicolons. Some coders use this form to save program file real estate, but it usually makes for more readable code if you stick to one statement per line for most of your work:

x = 1; y = 2; print x            # More than one simple statement

And finally, Python lets you move a compound statement’s body up to the header line, provided the body is just a simple (non-compound) statement. You’ll see this most often used for simple if statements with a single test and action:

if 1: print 'hello'              # Simple statement on header line

You can combine some of these special cases to write code that is difficult to read, but we don’t recommend it; as a rule of thumb, try to keep each statement on a line of its own, and indent all except the simplest of blocks. Six months down the road, you’ll be happy you did.

Truth Tests

We introduced the notions of comparison, equality, and truth values in Chapter 7. Since if statements are the first statement that actually uses test results, we’ll expand on some of these ideas here. In particular, Python’s Boolean operators are a bit different from their counterparts in languages like C. In Python:

  • True means any nonzero number or nonempty object.

  • False means not true: a zero number, empty object, or None.

  • Comparisons and equality tests are applied recursively to data structures.

  • Comparisons and equality tests return 1 or 0 (true or false).

  • Boolean and and or operators return a true or false operand object.

In short, Boolean operators are used to combine the results of other tests. There are three Boolean expression operators in Python:

X and Y

Is true if both X and Y are true

X or Y

Is true if either X or Y are true

not X

Is true if X is false (the expression returns 1 or 0)

Here, X and Y may be any truth value or an expression that returns a truth value (e.g., an equality test, range comparison, and so on). Boolean operators are typed out as words in Python (instead of C’s &&, ||, and !). Boolean and and or operators return a true or false object in Python, not an integer 1 or 0. Let’s look at a few examples to see how this works:

>>> 2 < 3, 3 < 2        # Less-than: return 1 or 0 
(1, 0)

Magnitude comparisons like these return an integer 1 or 0 as their truth value result. But and and or operators always return an object instead. For or tests, Python evaluates the operand objects from left to right, and returns the first one that is true. Moreover, Python stops at the first true operand it finds; this is usually called short-circuit evaluation, since determining a result short-circuits (terminates) the rest of the expression:

>>> 2 or 3, 3 or 2      # Return left operand if true.
(2, 3)                  # Else return right operand (true or false).
>>> [  ] or 3
3
>>> [  ] or {  }
{  }

In the first line above, both operands are true (2, 3), so Python always stops and returns the one on the left. In the other two tests, the left operand is false, so Python simply evaluates and returns the object on the right (which will happen to have a true or false value if tested). Also, and operations stop as soon as the result is known; in this case, Python evaluates operands from left to right and stops at the first false object:

>>> 2 and 3, 3 and 2    # Return left operand if false.
(3, 2)                  # Else return right operand (true or false).
>>> [  ] and {  }
[  ]
>>> 3 and [  ]
[  ]

Here, both operands are true in the first line, so Python evaluates both sides and returns the object on the right. In the second test, the left operand is false ([ ]), so Python stops and returns it as the test result. In the last test, the left side is true (3), so Python evaluates and returns the object on the right (which happens to be a false [ ]).

The end result of all this is the same as in C and most other languages—you get a value that is logically true of false, if tested in an if or while. However, in Python, Booleans return either the left or right object, not an integer flag.

One final note: as described in Chapter 7, Python 2.3 includes a new Boolean type, named bool, which is internally a subclass of the int integer type, with values True and False. These two instances are really just customized versions of integers 1 and 0, which yield the words True and False when printed or otherwise converted to strings. The only time you’ll generally notice this change is when you see Boolean outputs printed as True and False. More on type subclassing in Chapter 23.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.195.97