# Decisions and Selection¶

## Boolean Values and Boolean Expressions¶

The Python type for storing true and false values is called bool, named after the British mathematician, George Boole. George Boole created Boolean Algebra, which is the basis of all modern computer arithmetic.

There are only two boolean values. They are True and False. Capitalization is important, since true and false are not boolean values (remember Python is case sensitive).

(ch05_1)




Note

Boolean values are not strings!

It is extremely important to realize that True and False are not strings. They are not surrounded by quotes. They are the only two values in the data type bool. Take a close look at the types shown below.

(ch05_1a)




A boolean expression is an expression that evaluates to a boolean value. The equality operator, ==, compares two values and produces a boolean value related to whether the two values are equal to one another.

(ch05_2)




In the first statement, the two operands are equal, so the expression evaluates to True. In the second statement, 5 is not equal to 6, so we get False.

The == operator is one of six common comparison operators; the others are:

x != y               # x is not equal to y
x > y                # x is greater than y
x < y                # x is less than y
x >= y               # x is greater than or equal to y
x <= y               # x is less than or equal to y


Although these operations are probably familiar to you, the Python symbols are different from the mathematical symbols. A common error is to use a single equal sign (=) instead of a double equal sign (==). Remember that = is an assignment operator and == is a comparison operator. Also, there is no such thing as =< or =>.

Note too that an equality test is symmetric, but assignment is not. For example, if a == 7 then 7 == a. But in Python, the statement a = 7 is legal and 7 = a is not. (Can you explain why?)

sel-1: Which of the following is a Boolean expression? Select all that apply.

## Logical operators¶

There are three logical operators: and, or, and not. The semantics (meaning) of these operators is similar to their meaning in English. For example, x > 0 and x < 10 is true only if x is greater than 0 and at the same time, x is less than 10. How would you describe this in words? You would say that x is between 0 and 10, not including the endpoints.

n % 2 == 0 or n % 3 == 0 is true if either of the conditions is true, that is, if the number is divisible by 2 or divisible by 3. In this case, one, or the other, or both of the parts has to be true for the result to be true.

Finally, the not operator negates a boolean expression, so not  x > y is true if x > y is false, that is, if x is less than or equal to y.

(chp05_3)




Common Mistake!

There is a very common mistake that occurs when programmers try to write boolean expressions. For example, what if we have a variable number and we want to check to see if its value is 5,6, or 7. In words we might say: “number equal to 5 or 6 or 7”. However, if we translate this into Python, number == 5 or 6 or 7, it will not be correct. The or operator must join the results of three equality checks. The correct way to write this is number == 5 or number == 6 or number == 7. This may seem like a lot of typing but it is absolutely necessary. You cannot take a shortcut.

sel-2: What is the correct Python expression for checking to see if a number stored in a variable x is between 0 and 5.

## Precedence of Operators¶

We have now added a number of additional operators to those we learned in the previous chapters. It is important to understand how these operators relate to the others with respect to operator precedence. Python will always evaluate the arithmetic operators first (** is highest, then multiplication/division, then addition/subtraction). Next comes the relational operators. Finally, the logical operators are done last. This means that the expression x*5 >= 10 and y-6 <= 20 will be evaluated so as to first perform the arithmetic and then check the relationships. The and will be done last. Although many programmers might place parenthesis around the two relational expressions, it is not necessary.

The following table summarizes the operator precedence from highest to lowest. A complete table for the entire language can be found in the Python Documentation.

Level Category Operators
7(high) exponent **
6 multiplication *,/,//,%
4 relational ==,!=,<=,>=,>,<
3 logical not
2 logical and
1(low) logical or

Note

This workspace is provided for your convenience. You can use this activecode window to try out anything you like.

(scratch_06_01)




sel-3: Which of the following properly expresses the precedence of operators (using parentheses) in the following expression: 5*3 > 10 and 4+6==11

## Conditional Execution: Binary Selection¶

In order to write useful programs, we almost always need the ability to check conditions and change the behavior of the program accordingly. Selection statements, sometimes also referred to as conditional statements, give us this ability. The simplest form of selection is the if statement. This is sometimes referred to as binary selection since there are two possible paths of execution.

(ch05_4)




The syntax for an if statement looks like this:

if BOOLEAN EXPRESSION:
STATEMENTS_1        # executed if condition evaluates to True
else:
STATEMENTS_2        # executed if condition evaluates to False


The boolean expression after the if statement is called the condition. If it is true, then the indented statements get executed. If not, then the statements indented under the else clause get executed.

As with the function definition from the last chapter and other compound statements like for, the if statement consists of a header line and a body. The header line begins with the keyword if followed by a boolean expression and ends with a colon (:).

The indented statements that follow are called a block. The first unindented statement marks the end of the block.

Each of the statements inside the first block of statements is executed in order if the boolean expression evaluates to True. The entire first block of statements is skipped if the boolean expression evaluates to False, and instead all the statements under the else clause are executed.

There is no limit on the number of statements that can appear under the two clauses of an if statement, but there has to be at least one statement in each block.

Lab

• Approximating Pi with Simulation In this guided lab exercise we will work through a problem solving exercise related to approximating the value of pi using random numbers.

sel-4: How many statements can appear in each block (the if and the else) in a conditional statement?

sel-5: What does the following code print (choose from output a, b, c or nothing).

if (4 + 5 == 10):
print("TRUE")
else:
print("FALSE")


sel-6: What does the following code print?

if (4 + 5 == 10):
print("TRUE")
else:
print("FALSE")
print("TRUE")

a. TRUE

b.
TRUE
FALSE

c.
FALSE
TRUE
d.
TRUE
FALSE
TRUE

## Omitting the else Clause: Unary Selection¶

Another form of the if statement is one in which the else clause is omitted entirely. This creates what is sometimes called unary selection. In this case, when the condition evaluates to True, the statements are executed. Otherwise the flow of execution continues to the statement after the body of the if.

(ch05_unaryselection)




What would be printed if the value of x is negative? Try it.

sel-7: What does the following code print?

x = -10
if x < 0:
print("The negative number ",  x, " is not valid here.")
print("This is always printed")

a.
This is always printed

b.
The negative number -10 is not valid here
This is always printed

c.
The negative number -10 is not valid here

sel-8: Will the following code cause an error?

x = -10
if x < 0:
print("The negative number ",  x, " is not valid here.")
else:
print(x, " is a positive number")
else:
print("This is always printed")


## Nested conditionals¶

One conditional can also be nested within another. For example, assume we have two integer variables, x and y. The following pattern of selection shows how we might decide how they are related to each other.

if x < y:
print("x is less than y")
else:
if x > y:
print("x is greater than y")
else:
print("x and y must be equal")


The outer conditional contains two branches. The second branch (the else from the outer) contains another if statement, which has two branches of its own. Those two branches could contain conditional statements as well.

The flow of control for this example can be seen in this flowchart illustration.

Here is a complete program that defines values for x and y. Run the program and see the result. Then change the values of the variables to change the flow of control.

(sel2)




Note

In some programming languages, matching the if and the else is a problem. However, in Python this is not the case. The indentation pattern tells us exactly which else belongs to which if.

If you are still a bit unsure, here is the same selection as part of a codelens example. Step through it to see how the correct print is chosen.

(sel1)

sel-9: Will the following code cause an error?

x = -10
if x < 0:
print("The negative number ",  x, " is not valid here.")
else:
if x > 0:
print(x, " is a positive number")
else:
print(x," is 0")


## Chained conditionals¶

Python provides an alternative way to write nested selection such as the one shown in the previous section. This is sometimes referred to as a chained conditional

if x < y:
print("x is less than y")
elif x > y:
print("x is greater than y")
else:
print("x and y must be equal")


The flow of control can be drawn in a different orientation but the resulting pattern is identical to the one shown above.

elif is an abbreviation of else if. Again, exactly one branch will be executed. There is no limit of the number of elif statements but only a single (and optional) final else statement is allowed and it must be the last branch in the statement.

Each condition is checked in order. If the first is false, the next is checked, and so on. If one of them is true, the corresponding branch executes, and the statement ends. Even if more than one condition is true, only the first true branch executes.

Here is the same program using elif.

(sel4)




Note

This workspace is provided for your convenience. You can use this activecode window to try out anything you like.

(scratch_06_02)




sel-10: Which of I, II, and III below gives the same result as the following nested if?

# nested if-else statement
x = -10
if x < 0:
print("The negative number ",  x, " is not valid here.")
else:
if x > 0:
print(x, " is a positive number")
else:
print(x, " is 0")

I.

if x < 0:
print("The negative number ",  x, " is not valid here.")
else (x > 0):
print(x, " is a positive number")
else:
print(x, " is 0")

II.

if x < 0:
print("The negative number ",  x, " is not valid here.")
elif (x > 0):
print(x, " is a positive number")
else:
print(x, " is 0")

III.

if x < 0:
print("The negative number ",  x, " is not valid here.")
if (x > 0):
print(x, " is a positive number")
else:
print(x, " is 0")


sel-11: What will the following code print if x = 3, y = 5, and z = 2?

if x < y and x < z:
print ("a")
elif y < x and y < z:
print ("b")
else:
print ("c")


## Boolean Functions¶

We have already seen that boolean values result from the evaluation of boolean expressions. Since the result of any expression evaluation can be returned by a function (using the return statement), functions can return boolean values. This turns out to be a very convenient way to hide the details of complicated tests. For example:

(ch06_boolfun1)




The name of this function is isDivisible. It is common to give boolean functions names that sound like yes/no questions. isDivisible returns either True or False to indicate whether the x is or is not divisible by y.

We can make the function more concise by taking advantage of the fact that the condition of the if statement is itself a boolean expression. We can return it directly, avoiding the if statement altogether:

def isDivisible(x, y):
return x % y == 0


Boolean functions are often used in conditional statements:

if isDivisible(x, y):
... # do something ...
else:
... # do something else ...


It might be tempting to write something like if isDivisible(x, y) == True: but the extra comparison is not necessary. The following example shows the isDivisible function at work. Notice how descriptive the code is when we move the testing details into a boolean function. Try it with a few other actual parameters to see what is printed.

(ch06_boolfun2)




Here is the same program in codelens. When we evaluate the if statement in the main part of the program, the evaluation of the boolean expression causes a call to the isDivisible function. This is very easy to see in codelens.

(ch06_boolcodelens)

sel-12: What is a Boolean function?

sel-13: Is the following statement legal in Python (assuming x, y and z are defined to be numbers)?

return x + y < z


Note

This workspace is provided for your convenience. You can use this activecode window to try out anything you like.

(scratch_06_03)




## Glossary¶

block
A group of consecutive statements with the same indentation.
body
The block of statements in a compound statement that follows the header.
boolean expression
An expression that is either true or false.
boolean function
A function that returns a boolean value. The only possible values of the bool type are False and True.
boolean value
There are exactly two boolean values: True and False. Boolean values result when a boolean expression is evaluated by the Python interepreter. They have type bool.
branch
One of the possible paths of the flow of execution determined by conditional execution.
chained conditional
A conditional branch with more than two possible flows of execution. In Python chained conditionals are written with if ... elif ... else statements.
comparison operator
One of the operators that compares two values: ==, !=, >, <, >=, and <=.
condition
The boolean expression in a conditional statement that determines which branch is executed.
conditional statement
A statement that controls the flow of execution depending on some condition. In Python the keywords if, elif, and else are used for conditional statements.
logical operator
One of the operators that combines boolean expressions: and, or, and not.
modulus operator
An operator, denoted with a percent sign ( %), that works on integers and yields the remainder when one number is divided by another.
nesting
One program structure within another, such as a conditional statement inside a branch of another conditional statement.

## Exercises¶

1. What do these expressions evaluate to?

1. 3 == 3

2. 3 != 3

3. 3 >= 4

4. not (3 < 4)

(ex_6_1)



1. True
2. False
3. False
4. False
2. Give the logical opposites of these conditions. You are not allowed to use the not operator.

1. a > b

2. a >= b

3. a >= 18  and  day == 3

4. a >= 18  or  day != 3

(ex_6_2)



3. Write a function which is given an exam mark, and it returns a string — the grade for that mark — according to this scheme:

Mark

>= 90

A

[80-90)

B

[70-80)

C

[60-70)

D

< 60

F

The square and round brackets denote closed and open intervals. A closed interval includes the number, and open interval excludes it. So 79.99999 gets grade C , but 80 gets grade B.

Test your function by printing the mark and the grade for a number of different marks.

(ex_6_3)




(q3_question)



4. Modify the turtle bar chart program from the previous chapter so that the bar for any value of 200 or more is filled with red, values between [100 and 200) are filled yellow, and bars representing values less than 100 are filled green.

(ex_6_4)



5. In the turtle bar chart program, what do you expect to happen if one or more of the data values in the list is negative? Go back and try it out. Change the program so that when it prints the text value for the negative bars, it puts the text above the base of the bar (on the 0 axis).

(ex_6_5)






6. Write a function findHypot. The function will be given the length of two sides of a right-angled triangle and it should return the length of the hypotenuse. (Hint: x ** 0.5 will return the square root, or use sqrt from the math module)

(ex_6_6)



7. Write a function called is_even(n) that takes an integer as an argument and returns True if the argument is an even number and False if it is odd.

(ex_6_7)






8. Now write the function is_odd(n) that returns True when n is odd and False otherwise.

(ex_6_8)



9. Modify is_odd so that it uses a call to is_even to determine if its argument is an odd integer.

(ex_6_9)






10. Write a function is_rightangled which, given the length of three sides of a triangle, will determine whether the triangle is right-angled. Assume that the third argument to the function is always the longest side. It will return True if the triangle is right-angled, or False otherwise.

Hint: floating point arithmetic is not always exactly accurate, so it is not safe to test floating point numbers for equality. If a good programmer wants to know whether x is equal or close enough to y, they would probably code it up as

if  abs(x-y) < 0.001:      # if x is approximately equal to y
...


(ex_6_10)



11. Extend the above program so that the sides can be given to the function in any order.

(ex_6_11)






12. A year is a leap year if it is divisible by 4 unless it is a century that is not divisible by 400. Write a function that takes a year as a parameter and returns True if the year is a leap year, False otherwise.

(ex_6_12)



13. Implement the calculator for the date of Easter.

The following algorithm computes the date for Easter Sunday for any year between 1900 to 2099.

Ask the user to enter a year. Compute the following:

1. a = year % 19
2. b = year % 4
3. c = year % 7
4. d = (19 * a + 24) % 30
5. e = (2 * b + 4 * c + 6 * d + 5) % 7
6. dateofeaster = 22 + d + e

Special note: The algorithm can give a date in April. Also, if the year is one of four special years (1954, 1981, 2049, or 2076) then subtract 7 from the date.

Your program should print an error message if the user provides a date that is out of range.

(ex_6_13)