Yet another thing our programs so far have not been able to do is change their behaviour based on certain conditions. More simply put, we want to be able to specify that our programs should execute one set of statements under certain conditions, and under other conditions those statements should be ignored. Now as always, we smart humans can come up with dozens of ways of specifying conditions;
Computers however are not so smart, and decidedly less flexible. In general a computer is aware of two, and only two, conditions: True and False. Now if your mind immediately leaps back to one of the five basic types of variables available in python, namely boolean, then congratulations, you're thinking like a programmer already!
In addition to computers only being aware of two conditions, programming languages generally have very few ways of determining what those conditions are and acting upon them. Python specifically has three methods, the most prevalent of which is the if statement. Put the following in a file called 'second.py':
x = raw_input("Enter a number: ") if x > '3': print "You entered", x print "'x' is larger than 3"
Now run your program using python second.py
and enter
'2' when prompted.
sirlark@hephaestus ~/scratch $ python second.py Enter a number: 2
Hmmmm! Why didn't our print statements execute? If, as we believe,
the program executes from top to bottom, the print statements should
have been executed. Obviously, that if x > '3':
is
doing something we are unaware of, so let's experiment a little more.
Run the program again, but this time enter '5' at the prompt.
sirlark@hephaestus ~/scratch $ python second.py Enter a number: 5 You entered 5 'x' is larger than 3
Okay! Our program just acted differently based on the input we gave it, or rather, based on the conditions determined by the input. Looking back at the last three lines of our program, there's a lot of new stuff in there that needs explanation, so we'll break it down. The if statement takes the format:
if <expression>: statement statement ...
What 'if' does, is check whether the expression provided has a value
of True, and if so, the statement immediately following is
executed, otherwise it is not executed. Now you might be thinking, how
can a number be true or false? Well if we look carefully at our
expression x > '3'
we see that we have in fact made a
logical proposition. We propose that the value of 'x' is greater than
3. The if statement checks whether the proposition,
often also called a boolean expression (in reference
to the type of its value), is true and acts accordingly. Propositions
are simply specialised forms of expressions that have a value of either
True or False.
'True' and 'False' are special words to python, known as reserved words, meaning they have been reserved for a particular purpose. Other reserved words we have encountered include 'print', and 'if'. The complete list of python's reserved words can be found here.
Note that when forming our proposition we used a specific operator, the greater than sign ('>'). When forming propositions we can use a specific set of operators, called comparison operators. If both 'a' and 'b' are expressions of any type:
a == b
proposes Equivalence. Is 'a' equal to 'b'?
Note the double equals. In python '=' means
assignment, and '==' means 'is equal to'.a != b
proposes Non-equivalence. Is 'a' not equal
to 'b'?a < b
proposes Less Than. Is 'a' less than
'b'?a > b
proposes Greater Than. Is 'a' greater
than 'b'?a <= b
proposes Less Than OR Equal To. Is 'a'
less than or equal to 'b'?a >= b
proposes Greater Than OR Equal To. Is
'a' greater than or equal to 'b'?a in b
proposes that the string a
is a substring of, i.e. exists inside, the
string 'b'.
Propositions, being expressions themselves, follow the usual rules
for composition of expressions. This means that we can have an
expression, (x > 3) == (y < 4)
, in which we have two
propositions 'x > 3' and 'y < 4' which have been composed into
the total expression. The entire proposition is true only if both the
sub-propositions have the same truth value at the time the expression
is evaluated.
Theoretically we could use arithmetic operators to compose
propositions in the same way we do arithmetic expressions, as in
(x == 3) + (y == 4)
. But in practice this doesn't work, as
the arithmetic operators promote the truth values to integers, where
True is 1 and False is 0. So what we actually get is
>>> x = 3 >>> y = 4 >>> (x == 3) + (y == 4) 2 >>>
Instead we must use logical operators, also known as boolean operators, to compose propositions. There are only three logical operators, listed below. If 'expr1' and 'expr2' are both propositions:
expr1 and expr2
is True if both 'expr1'
and 'expr2' are True when the proposition is
evaluated.expr1 or expr2
is True if either 'expr1'
or 'expr2' are True when the proposition is
evaluated.not expr1
is True if 'expr1' is False, and vice
versa.Using these logical operators we are now able to express very detailed and precise conditions to be checked by the if statement. Taking our previously expressed English examples:
We can now express them in python as follows
if weather == 'raining': pass #don't go out
if (num_traffic_lights_passed == 2) and (location_type == 'traffic lights'): pass #turn left
Hmmm, we still don't have a good way to express 'when', but we'll
get there. In the meanwhile, note the statement pass
. Pass
is another reserved word in python, and means quite simply 'do
nothing'. We need it because 'if statements' require a
statement to execute if the expression they evaluate is True.
We need to be aware of some common pitfalls that we will encounter when translating English language logic (forgive the oxymoron) into mathematical or computer logic. Examine the following examples:
Note that all expressions in python have a truth value. In general,
any expression with a non-zero value is considered to be true.
Specifically; 0, the empty string (''), None, and empty sequences or
containers (we'll cover these later) are all considered False. Every
other value for an expression is true. This actually means that
expressions such as (x > 3) and (7)
are valid as
propositions, and in fact are often meaningful too, especially when
checking for non-zero or non-empty variables. It does however mean that
the wrong examples listed above are valid code but evaluate to something
totally different from what we want.
Check out the python documentation page on boolean operators for more detailed information.
Examining what we said previously, we notice nasty phrases like 'the statement', indicating one, singular, statement. However, most of the time we actually want to execute a number of statements under certain conditions, and none of those statements if the aforementioned conditions are not met. Python, like most programming languages, provides us with the ability to group collections of statements into blocks, much like composition of expressions. Such blocks can be treated as a single statement for the purposes of if statements, and others we will encounter soon.
Unlike most other languages python allows us to specify blocks using indentation. Lines of code that have the same indentation are considered to be members of the same block. Blocks can also be nested inside one another, such lines constituting inner blocks are also members of their encompassing outer blocks. This is best illustrated using an example. (line numbers are not part of the code)
1: #this program takes three numbers as input, and counts how many of 2: #those numbers is even, and how many even numbers are negative 3: #if an even number is entered, if it is negative, a message is printed 4: 5: #set the counts for even and negative to 0 6: even = 0 7: negative = 0 8: 9: #get the first number 10: first = int(raw_input("Enter the first number: ")) 11: if first % 2 == 0: 12: print "The first number is even" 13: even = even + 1 14: if first < 0: 15: print "The first number is negative" 16: negative = negative + 1 17: 18: #get the second number 19: second = int(raw_input("Enter the second number: ")) 20: if second % 2 == 0: 21: print "The second number is even" 22: even = even + 1 23: if second < 0: 24: print "The second number is negative" 25: negative = negative + 1 26: 27: #get the third number 28: third = int(raw_input("Enter the third number: ")) 29: if third % 2 == 0: 30: print "The third number is even" 31: even = even + 1 32: if third < 0: 33: print "The third number is negative" 34: negative = negative + 1 35: 36: print "There were", even, "even numbers and", negative, "negative numbers"
Running this program and giving the numbers 2, -4, and 7 as input produces
sirlark@hephaestus ~/scratch $ python illus.py Enter the first number: 2 The first number is even Enter the second number: -4 The second number is even The second number is negative Enter the third number: 7 There were 2 even numbers and 1 negative numbers
Firstly, let's get the indentation and nesting thing out of the way. Looking at lines 12 through to 16 we see they are more indented than the if statement on line 11. Thus these lines form a block of statements. Since this block is immediately after an if statement, all the statements in the block will only be executed if the if statement's expression is True. For the first number we gave as input (2), this is the case, so we start executing the block. When we get to line 14 we encounter a second if statement. This second if statement is nested inside the first, because it will only be executed if the outer if statement (line 11) has an expression that evaluates to True. Lines 15 and 16 form a nested block, but are not executed because 2 is not negative, or more specifically because 2 is not less than 0. Conversely, lines 24 and 25 will be executed because -4 is less than 0.
Despite the fact that this example is an order of magnitude larger
than any previous examples, there are only two new things. The first
being indentation and nesting, the second being the use of
int()
around our raw_input functions. Remember that
raw_input() returns a string. So even if the user types in 2,
raw_input() returns not 2 but the string '2'. Strings and numbers don't
really play nice together, especially when they're being compared to
one another, so we need to convert the string into an integer. This is
known as type casting or coercion. We
can do it for any basic python type ...
>>> float("3.1415") 3.1415 >>> str(143) '143' >>> bool(None) False >>> bool(-1) True >>>
So now we have a handle on basic if statements, we come up against the next hurdle. If our condition isn't met, our if block statements simply aren't executed. But what if we want something else executed instead of nothing when the condition isn't met. Enter the if ... else statement.
1: first = int(raw_input("Enter a number: ")) 2: if first % 2 == 0: 3: print first, "is even" 4: else: 5: print first, "is odd"
Now, if 'first' is not even, the program will print a message saying it is odd, instead of doing nothing. The indentation is of key importance here again. Note that 'else' is at the same indentation level as the 'if' and is also followed by a colon (':'). The statement to be executed if 'first' is not even, on line 5, is known as the else clause, as the statement on line 3 is known as the if clause.
Finally we have to deal with the case where things are not as clear cut, not so black and white.
1: colour = raw_input("Enter the name of a colour: ") 2: if colour == "Red": 3: print "Red is a primary colour" 4: elif colour == "Green": 5: print "Green is a primary colour" 6: elif colour == "Blue": 7: print "Blue is a primary colour" 8: else: 9: print colour, "is not a primary Colour"
Running this a couple of with various inputs we get
sirlark@hephaestus ~/scratch $ python illus.py Enter the name of a colour: Red Red is a primary colour sirlark@hephaestus ~/scratch $ python illus.py Enter the name of a colour: Green Green is a primary colour sirlark@hephaestus ~/scratch $ python illus.py Enter the name of a colour: blue blue is not a primary Colour sirlark@hephaestus ~/scratch $
The first run things happen as expected; We get to line 2, the value of colour is Red, the expression for the if statement is True, we execute line 3 ... and then the program finishes! This is because line 4 is not part of the block constituting line 2's if clause, because it has a lower indentation level. Also line's 4, 6 and 8 are all still part of the same if statement. Let's look at the second run a little more closely to see what happens.
We get to line 2, the value of colour is Green. Green is not equal to Red, so we don't execute line 3. Instead we jump to the else ... hang on! What is 'elif'? 'elif' is short for 'else if' and allows one to set up alternate conditions if earlier conditions haven't been met. So we get to the 'elif' on line 4. Green is Green so we execute line 5.
The third run illustrates nicely that in fact strings in python are case sensitive too. Not just the language, but the data we manipulate with it is considered case sensitive. 'Blue' and 'blue' are different strings.
if <expression>: statement statement ... [elif <expression>: statement statement ...] [elif <expression>: statement statement ...] [...] [else: statement statement ...]
if c in 'acgt': print c, 'is a nucleotide base'