Conditionals

# Conditionals

Source: this section is heavily based on Chapter 5 of [ThinkCS].

Until now, we have seen how to write programs that consist of assignment statements. In these programs, we always execute all statements in the program one after the other. Programs get much more interesting when we can test conditions and change the program behaviour depending on the outcome of the tests. That's what this chapter is about.

A core idea in the conditional execution of statements is that we want to execute certain parts of code only when a condition is satisfied. Essentially, we want to test whether a condition is satisfied; if so, we do one thing; if not, we do another thing.

# Boolean values and expressions

To write down conditions, a fundamental idea in Python is that conditions can also be seen as expressions; they are expressions that generate an outcome that can either be True or False. We refer to these values as Boolean values. They are named after the British mathematician, George Boole, who first formulated Boolean algebra --- some rules for reasoning about and combining these values. This is the basis of all modern computer logic. ` We can store conditions in variables; the type of such variables is bool.

```>>> type(True)
<class 'bool'>
>>> type(true)
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
NameError: name 'true' is not defined
```

A Boolean expression is an expression that evaluates to produce a result which is a Boolean value. For example, the operator == tests if two values are equal. It produces (or yields) a Boolean value:

```>>> 5 == (3 + 2)   # Is five equal 5 to the result of 3 + 2?
True
>>> 5 == 6
False
>>> j = "hel"
>>> j + "lo" == "hello"
True
```

In the first statement, the two operands evaluate to equal values, 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 which all produce a bool result; here are all six:

```x == y               # Produce True if ... x is equal to y
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, 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 =>.

Like any other types we've seen so far, Boolean values can be assigned to variables, printed, etc.

```>>> age = 18
>>> old_enough_to_get_driving_licence = age >= 17
>>> print(old_enough_to_get_driving_licence)
True
>>> type(old_enough_to_get_driving_licence)
<class 'bool'>
```

# Logical operators

There are three logical operators, and, or, and not, that allow us to build more complex Boolean expressions from simpler Boolean expressions. The semantics (meaning) of these operators is similar to their meaning in English. For example, x > 0 and x < 10 produces True only if x is greater than 0 and at the same time, x is less than 10.

n % 2 == 0 or n % 3 == 0 is True if either of the conditions is True, that is, if the number n is divisible by 2 or it is divisible by 3. (What do you think happens if n is divisible by both 2 and by 3 at the same time? Will the expression yield True or False? Try it in your Python interpreter.)

Finally, the not operator negates a Boolean value, so not (x > y) is True if (x > y) is False, that is, if x is less than or equal to y.

The expression on the left of the or operator is evaluated first: if the result is True, Python does not (and need not) evaluate the expression on the right --- this is called short-circuit evaluation. Similarly, for the and operator, if the expression on the left yields False, Python does not evaluate the expression on the right.

So there are no unnecessary evaluations.

# Truth Tables

A truth table is a small table that allows us to list all the possible inputs, and to give the results for the logical operators. Because the and and or operators each have two operands, there are only four rows in a truth table that describes the semantics of and.

a b a and b
False False False
False True False
True False False
True True True

In a Truth Table, we sometimes use T and F as shorthand for the two Boolean values: here is the truth table describing or:

a b a or b
F F F
F T T
T F T
T T T

The third logical operator, not, only takes a single operand, so its truth table only has two rows:

a not a
F T
T F

# Simplifying Boolean Expressions

A set of rules for simplifying and rearranging expressions is called an algebra. For example, we are all familiar with school algebra rules, such as:

```n * 0 == 0
```

Here we see a different algebra --- the Boolean algebra --- which provides rules for working with Boolean values.

First, the and operator:

```x and False == False
False and x == False
y and x == x and y
x and True == x
True and x == x
x and x == x
```

Here are some corresponding rules for the or operator:

```x or False == x
False or x == x
y or x == x or y
x or True == True
True or x == True
x or x == x
```

Two not operators cancel each other:

```not (not x) == x
```

# Conditional execution

In order to write useful programs, we almost always need the ability to check conditions and change the behavior of the program accordingly. Conditional statements give us this ability. The simplest form is the if statement:

```if x % 2 == 0:
print(x, " is even.")
print("Did you know that 2 is the only even number that is prime?")
else:
print(x, " is odd.")
print("Did you know that multiplying two odd numbers " +
"always gives an odd result?")
```

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

Flowchart of an if statement with an else clause 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
```

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 are 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 indented 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. Occasionally, it is useful to have a section with no statements (usually as a place keeper, or scaffolding, for code we haven't written yet). In that case, we can use the pass statement, which does nothing except act as a placeholder.

```if True:          # This is always True,
pass          #   so this is always executed, but it does nothing
else:
pass
```

# Omitting the else clause

Flowchart of an if statement with no else clause Another form of the if statement is one in which the else clause is omitted entirely. In this case, when the condition evaluates to True, the statements are executed, otherwise the flow of execution continues to the statement after the if.

```if x < 0:
print("The negative number ",  x, " is not valid here.")
x = 42
print("I've decided to use the number 42 instead.")

print("The square root of ", x, "is", math.sqrt(x))
```

In this case, the print function that outputs the square root is the one after the if --- not because we left a blank line, but because of the way the code is indented. Note too that the function call math.sqrt(x) will give an error unless we have an import math statement, usually placed near the top of our script.

Python terminology

Python documentation sometimes uses the term suite of statements to mean what we have called a block here. They mean the same thing, and since most other languages and computer scientists use the word block, we'll stick with that.

Notice too that else is not a statement. The if statement has two clauses, one of which is the (optional) else clause.

# The while statement

The if statement allows to make a choice between two blocks of code. However, in a program that only contains assignment and if statements, every statement is still executed at most one. It is very common that we want the computer to repeat statements multiple times. The most basic statement that allows to do so, is the while statement.

However, before introducing the while statement, it is good remind ourselves of some important aspects of assignments.

# Assignment vs Boolean Expressions

As we have mentioned previously, it is legal to make more than one assignment to the same variable. A new assignment makes an existing variable refer to a new value (and stop referring to the old value).

```airtime_remaining = 15
print(airtime_remaining)
airtime_remaining = 7
print(airtime_remaining)
```

The output of this program is:

```15
7
```

because the first time airtime_remaining is printed, its value is 15, and the second time, its value is 7.

It is especially important to distinguish between an assignment statement and a Boolean expression that tests for equality. Because Python uses the equal token (=) for assignment, it is tempting to interpret a statement like a = b as a Boolean test. Unlike mathematics, it is not! Remember that the Python token for the equality operator is ==.

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.

In Python, an assignment statement can make two variables equal, but because further assignments can change either of them, they don't have to stay that way:

```a = 5
b = a    # After executing this line, a and b are now equal
a = 3    # After executing this line, a and b are no longer equal
```

The third line changes the value of a but does not change the value of b, so they are no longer equal. (In some programming languages, a different symbol is used for assignment, such as <- or :=, to avoid confusion.) Some people also think that variable was an unfortunate word to choose, and instead we should have called them assignables. Python chooses to follow common terminology and token usage, also found in languages like C, C++, Java, and C#, so we use the tokens = for assignment, == for equality, and we talk of variables.

# Updating variables

When an assignment statement is executed, the right-hand side expression (i.e. the expression that comes after the assignment token) is evaluated first. This produces a value. Then the assignment is made, so that the variable on the left-hand side now refers to the new value.

One of the most common forms of assignment is an update, where the new value of the variable depends on its old value.

```n = 5
n = 3 * n + 1
```

Line 2 means get the current value of n, multiply it by three and add one, and assign the answer to n, thus making n refer to the value. So after executing the two lines above, n will point/refer to the integer 16.

If you try to get the value of a variable that has never been assigned to, you'll get an error:

```>>> w = x + 1
Traceback (most recent call last):
File "<interactive input>", line 1, in
NameError: name 'x' is not defined
```

Before you can update a variable, you have to initialize it to some starting value, usually with a simple assignment:

```runs_scored = 0
...
runs_scored = runs_scored + 1
```

Line 3 --- updating a variable by adding 1 to it --- is very common. It is called an increment of the variable; subtracting 1 is called a decrement. Sometimes programmers also talk about bumping a variable, which means the same as incrementing it by 1.

# Structure of the while

Now that we have pointed out some important aspects of assignments, we are ready to introduce the while statement, which allows to repeat lines of code.

Here is a fragment of code that demonstrates the use of the while statement:

```n = 4
""" Determine the sum of 1+2+3 ... n """
ss = 0
v = 1
while v <= n:
ss = ss + v
v = v + 1
print(v)
```

When executing this code, the value 10 (1+2+3+4) will be printed on the screen.

You can almost read the while statement as if it were English. It means, while v is less than or equal to n, continue executing the body of the loop. Within the body, each time, increment v. When v passes n, return your accumulated sum.

More formally, here is precise flow of execution for a while statement:

• Evaluate the condition at line 5, yielding a value which is either False or True.
• If the value is False, exit the while statement and continue execution at the next statement (line 8 in this case).
• If the value is True, execute each of the statements in the body (lines 6 and 7) and then go back to the while statement at line 5.

The body consists of all of the statements indented below the while keyword.

Notice that if the loop condition is False the first time we get loop, the statements in the body of the loop are never executed.

The body of the loop should change the value of one or more variables so that eventually the condition becomes false and the loop terminates. Otherwise the loop will repeat forever, which is called an infinite loop. An endless source of amusement for computer scientists is the observation that the directions on shampoo, "lather, rinse, repeat", are an infinite loop.

In the case here, we can prove that the loop terminates because we know that the value of n is finite, and we can see that the value of v increments each time through the loop, so eventually it will have to exceed n. In other cases, it is not so easy, even impossible in some cases, to tell if the loop will ever terminate.

In general, a common construct in many programs is the following:

```i = 1
while i <= n:
STATEMENTS
i  = i + 1
```

In this case, we will execute the indicated STATEMENTS n times. However, note that it is possible to use any Boolean expression as a condition; the following is hence also a valid program:

```while x >= 0:
STATEMENTS
x = x // 2
```

In this code, we will continue to divide a number x by 2, as long as the outcome of the division is not 2. The power of the while statement is hence that we are very free in how we specify how many times a block of statement is repeated!

# 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 algebra
Some rules for rearranging and reasoning about Boolean expressions.
Boolean expression
An expression that is either true or false.
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.
comparison operator
One of the six 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.
counter
A variable used to count something, usually initialized to zero and incremented in the body of a loop.
increment
Both as a noun and as a verb, increment means to increase by 1.
infinite loop
A loop in which the terminating condition is never satisfied.
indefinite iteration
A loop where we just need to keep going until some condition is met. A while statement is used for this case.
iteration
Repeated execution of a set of programming statements.
loop
The construct that allows allows us to repeatedly execute a statement or a group of statements until a terminating condition is satisfied.
loop variable
A variable used as part of the terminating condition of a loop.
logical operator
One of the operators that combines Boolean expressions: and, or, and not.
nesting
One program structure within another, such as a conditional statement inside a branch of another conditional statement.
prompt
A visual cue that tells the user that the system is ready to accept input data.
truth table
A concise table of Boolean values that can describe the semantics of an operator.
type conversion
An explicit function call that takes a value of one type and computes a corresponding value of another type.