2  Flow Control

Author

phonchi

Published

February 24, 2023

Open In Colab


2.1 Introduction

Last week, we learned the basics of individual instructions and that a program is just a series of instructions. But programming’s real strength isn’t just running one instruction after another. Based on how expressions evaluate, a program can decide to skip instructions, repeat them, or choose one of several instructions to run. In fact, you rarely want your programs to start from the first line of code and simply execute every line straight to the end. Flow control statements can decide which Python instructions to execute under which conditions.

These flow control statements directly correspond to the symbols in a flowchart. A flowchart usually has more than one way to go from the start to the end. The same is true for lines of code in a computer program. Flowcharts represent these branching points with diamonds, while the other steps (states) are represented with rectangles. The starting and ending steps are represented with rounded rectangles.

source: https://automatetheboringstuff.com/2e/chapter2/


But before you learn about flow control statements, you first need to learn how to represent those yes and no options and understand how to write those branching points as Python code. To that end, let’s explore Boolean values, comparison operators, and Boolean operators.

2.1.1 Boolean expressions

A boolean expression is an expression that is either true or false. The following examples use the operator ==, which compares two operands and produces True if they are equal and False otherwise:

5 == 5, 5 == 6

True and False are special values that belong to the class bool; they are not strings:

type(True), type(False)

The == operator is one of the comparison operators or relational operators; the others are:

Meaning
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
x is y x is the same as y
x is not y x is not the same as y

The Python symbols are different from the mathematical symbols for the same operations. A common error is to use a single equal sign = instead of a double equal sign ==. Remember that = is used in the assignment statement and == is a comparison operator. There is no such thing as =< or =>.

These operators evaluate to True or False depending on the values you give them and, therefore, can be used in the decision point as a condition statement.

print(42==42)
print(42==42.0)         # It will compare its value!
print(42=='42')         # int/float are always different from string
print(2!=3)
print('hello'=='Hello') # Python is case sensitive
print(42 < 100)
print(42 >= 100)

2.1.2 Boolean (Logical) Operators

The three Boolean operators (and, or, and not) are used to operate on Boolean values. Like comparison operators, they evaluate these expressions down to a Boolean value. Let’s explore these operators in detail.

Expression Evaluates to . . .
True and True True
True and False False
False and True False
False and False False
Expression Evaluates to . . .
True or True True
True or False True
False or True True
False or False False
Expression Evaluates to . . .
not True False
not False True
print((4 < 5) and (5 < 6))
print((6 < 5) or (9 < 6))
print((1 == 2) or (2 == 2))
print(not (1==3) and (3==4))

The computer will evaluate the left expression first, and then it will evaluate the right expression. When it knows the Boolean value for each, it will then evaluate the whole expression down to one Boolean value. The Boolean operators have an order of operations just like the math operators do. After any math and comparison operators evaluate, Python evaluates the not operators first, then the and operators, and then the or operators.

2.2 Elements of Flow Control

It can be shown that all programs could be written using three forms of control—namely, sequential execution, the selection statement and the repetition statement. This is the idea behind structured programming.

Flow control statements often start with a part called the condition and are always followed by a block of code called the clause or body. The Boolean expressions you’ve seen so far could all be considered conditions, which are the same thing as expressions; the condition is just a more specific name in the context of flow control statements. Conditions always evaluate down to a Boolean value, True or False. A flow control statement decides what to do based on whether its condition is True or False.

2.2.1 Blocks of Code

Lines of Python code can be grouped together in blocks. You can tell when a block begins and ends from the indentation of the lines of code. There are three rules for blocks.

  1. Blocks begin when the indentation increases.
  2. Blocks can contain other blocks.
  3. Blocks end when the indentation decreases to zero or to a containing block’s indentation.

Blocks are easier to understand by looking at some indented code, so let’s find the blocks in part of a small game program, shown here:

name = 'Mary'
password = 'swordfish'
if name == 'Mary':
    print('Hello, Mary')
    if password == 'swordfish':
        print('Access granted.')
    else:
        print('Wrong password.')

You can view the execution of this program at https://autbor.com/blocks/. The first block of code starts at the line print('Hello, Mary') and contains all the lines after it. Inside this block is another block, which has only a single line in it: print('Access Granted.'). The third block is also one line long: print('Wrong password.').

An IndentationError occurs if you have more than one statement in a block and those statements do not have the same indentation:

name = 'Mary'
password = 'swordfish'
if name == 'Mary':
  print('Hello, Mary')
    if password == 'swordfish':
        print('Access granted.')
    else:
        print('Wrong password.')

It is recomend to use four white spaces as the indentation

2.2.2 Conditional execution

The control statement affords us a mechanism for jumping from one part of a program to another. In higher-level languages like Python, this enables what is called control structures, syntax patterns that allow us to express algorithms more succinctly. One example of this is the if-statement. An if statement’s body (that is, the block following the if statement) will execute if the statement’s condition is True. The body is skipped if the condition is False.

In Python, an if statement consists of the following:

  • The if keyword
  • A condition (that is, an expression that evaluates to True or False)
  • A colon
  • Starting on the next line, an indented block of code (called the if body)

The boolean expression after the if statement is called the condition. We end the if statement with a colon character (:) and the line(s) after the if statement are indented. If the logical condition is true, then the indented statement gets executed. If the logical condition is false, the indented statement is skipped.

name = 'Mary'
if name == 'Alice':
    print('Hi, Alice.')
source: https://automatetheboringstuff.com/2e/chapter2/

A second form of the if statement is alternative execution, in which there are two possibilities and the condition determines which one gets executed. The syntax looks like this:

if name == 'Alice':
    print('Hi, Alice.')
else:
    print('Hello, stranger.')

You can also write the above code in one line using the ternary conditional operator:

print('Hi, Alice.') if name == 'Alice' else print('Hello, stranger.') # Note that we do not have colon in between!
source: https://automatetheboringstuff.com/2e/chapter2/

Since the condition must either be true or false, exactly one of the alternatives will be executed. The alternatives are called branches, because they are branches in the flow of execution.

Sometimes there are more than two possibilities and we need more than two branches. One way to express a computation like that is a chained conditional:

name = 'Carol'
age = 3000
if name == 'Alice':
    print('Hi, Alice.')
elif age < 12:
    print('You are not Alice, kidd.')
else:
    print('You are neither Alice nor a little kid.')

You can view the execution of this program at https://autbor.com/littlekid/. In plain English, this type of flow control structure would be “If the first condition is true, do this. Else, if the second condition is true, do that.

source: https://automatetheboringstuff.com/2e/chapter2/

2.2.3 Exercise 1: Write a code that allows the user to input row and column. The program prints ‘black’ or ‘white’ depending on the color of the specified row and column of the chessboard. Chess boards are 8 x 8 spaces in size, and the rows and columns in this program begin at 0 and end at 7. If the inputs for a row or column are outside the 0 to 7 range, it should print ‘out of board’!

source: https://inventwithpython.com/pythongently/images/image011.png
row = int(input("Enter row"))
column = int(input("Enter column"))
# If the column and row is out of bounds, print out of board:
if column ____ or column ___ or row ___ or row ____:
    print('out of board')
# If the even/oddness of the column and row match, print 'white':
____ column % _ == row % _:
    print('white')
# If they don't match, then print 'black':
____:
    print('black')

2.2.4 Loops and Iterations

You can make a block of code execute over and over again using a while statement. The code in a while body will be executed as long as the while statement’s condition is True. In code, a while statement always consists of the following:

  • The while keyword
  • A condition (that is, an expression that evaluates to True or False)
  • A colon
  • Starting on the next line, an indented block of code (called the while body)
spam = 0
while spam < 5:
    print('Hello, world.')
    spam += 1 # equivalent to spam = spam + 1

Augmented assignments abbreviate assignment expressions in which the same variable name appears on the left and right of the assignment’s = as above

source: https://automatetheboringstuff.com/2e/chapter2/

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

  1. Evaluate the condition, yielding True or False.

  2. If the condition is false, exit the while statement and continue execution at the next statement.

  3. If the condition is true, execute the body and then go back to step 1.

In the while loop, the condition is always checked at the start of each iteration (that is, each time the loop is executed). If the condition is True, then the body is executed, and afterward, the condition is checked again. The first time the condition is found to be False, the while body is skipped.

A common programming pattern is that we can run the program as long as the user wants by putting most of the program in a while loop. We’ll define a quit value and then keep the program running as long as the user has not entered the quit value:

prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter 'quit' to end the program. "
message = ""
while message != 'quit':
    message = input(prompt)
    print(message)

We first set up a variable message to keep track of whatever value the user enters. We define message as an empty string, "", so Python has something to check the first time it reaches the while line. The first time through the loop, the message is just an empty string, so Python enters the loop. At message = input(prompt), Python displays the prompt and waits for the user to enter their input. Whatever they enter is assigned to message and printed; then, Python reevaluates the condition in the while statement. As long as the user has not entered the word ‘quit’, the prompt is displayed again and Python waits for more input. When the user finally enters ‘quit’, Python stops executing the while loop and the program ends.

Note that Python considers 0, None, empty string, and empty container as False and all other things are True!

bool(""), bool(0), bool(None), bool(prompt), bool(12)

2.2.4.1 Using break to Exit a Loop

The above program works well, except that it prints the word ‘quit’ as if it were an actual message. In fact, there is a shortcut to getting the program execution to break out of a while loop’s body early. If the execution reaches a break statement, it immediately exits the while loop’s body. In code, a break statement simply contains the break keyword.

prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter 'quit' to end the program. "
message = ""
while True:
    message = input(prompt)
    if message == 'quit':
        break
    else:
        print(message)

The fourth line creates an infinite loop; it is a while loop whose condition is always True. After the program execution enters this loop, it will exit the loop only when a break statement is executed. (An infinite loop that never exits is a common programming bug.)

Just like before, this program asks the user to for the input. Now, however, while the execution is still inside the while loop, an if statement checks whether the message is equal to ‘quit’. If this condition is True, the break statement is run, and the execution moves out of the loop. Otherwise, the if statement’s body that contains the break statement is skipped, which again prints out the message. After that, the program execution jumps back to the start of the while statement to recheck the condition. Since this condition is merely the True Boolean value, the execution enters the loop to ask the user to type another message.

2.2.4.2 continue Statemet

Rather than breaking out of a loop entirely without executing the rest of its code, you can use the continue statement to return to the beginning of the loop based on the result of a conditional test. For example, consider a loop that counts from 1 to 10 but prints only the odd numbers in that range:

current_number = 0
while current_number < 10:
    current_number += 1
    if current_number % 2 == 0:
        continue
    else:
        print(current_number, end=' ')

First, we set current_number to 0. Because it’s less than 10, Python enters the while loop. Once inside the loop, we increment the count by 1, so current_number is 1. The if statement then checks the modulo of current_number and 2. If the modulo is 0, the continue statement tells Python to ignore the rest of the loop and return to the beginning. If the current_number is not divisible by 2, the rest of the loop is executed and Python prints the current_number.

Note that the built-in function print() displays its argument(s), then moves the cursor to the next line. You can change this behavior with the argument end. We used one space (’ ’), so each call to print displays the character’s value followed by one space.

If you ever run a program that has a bug causing it to get stuck in an infinite loop, press CTRL-C. This will send a KeyboardInterrupt error to your program and cause it to stop immediately.

2.2.4.3 “TRUTHY” and “FALSY” Values

Let us delve into the following program:

name = ''
while not name:
    print('Enter your name:')
    name = input()

print('How many guests will you have?')
numOfGuests = int(input())

if numOfGuests:
    print('Be sure to have enough room for all your guests.')
print('Done')

You can view the execution of this program at https://autbor.com/howmanyguests/. If the user enters a blank string for name, then the while statement’s condition will be True, and the program continues to ask for a name. If the value for numOfGuests is not 0, then the condition is considered to be True, and the program will print a reminder for the user. You could have entered not name != '' instead of not name, and numOfGuests != 0 instead of numOfGuests, but using the truthy and falsy values can make your code easier to read.

2.2.5 for Loops and the range() Function

The while loop keeps looping while its condition is True (which is the reason for its name), but what if you want to execute a block of code only a certain number of times? You can do this with a for loop statement and the range() function.

In code, a for statement looks something like for i in range(5): and includes the following:

  • The for keyword
  • A variable name
  • The in keyword
  • A call to the range() funtion with up to three integers passed to it (or an iterable object, which we will discuss later on)
  • A colon
  • Starting on the next line, an indented block of code (called the for body)

Let’s create a new program to help you see a for loop in action.

print('My name is')
for i in range(5):
    print('Jimmy Five Times (' + str(i) + ')')

You can view the execution of this program at https://autbor.com/fivetimesfor/. The code in the for loop’s body is run five times. The first time it is run, the variable i is set to 0. The print() call in the body will print Jimmy Five Times (0). After Python finishes an iteration through all the code inside the for loop’s body, the execution goes back to the top of the loop, and the for statement increments i by one. This is why range(5) results in five iterations through the body, with i being set to 0, then 1, then 2, then 3, and then 4. The variable i will go up to, but will not include, the integer passed to range().

You can actually use a while loop to do the same thing as a for loop; for loops are just more concise.

print('My name is')
i = 0
while i < 5:
    print('Jimmy Five Times (' + str(i) + ')')
    i = i + 1

2.2.5.1 The Starting, Stopping, and Stepping Arguments to range()

Some functions can be called with multiple arguments separated by a comma, and range() is one of them. This lets you change the integer passed to range() to follow any sequence of integers, including starting at a number other than zero.

for i in range(12, 16):
    print(i)

The range() function can also be called with three arguments. The first two arguments will be the start and stop values, and the third will be the step argument. The step is the amount that the variable is increased by after each iteration.

for i in range(0, 10, 2):
    print(i)

The range() function is flexible in the sequence of numbers it produces for for loops. For example , you can even use a negative number for the step argument to make the for loop count down instead of up.

for i in range(5, -1, -1):
    print(i)

Note that Python introduce switch statement as another control statement in Python 3.10

2.2.6 Exercise 2: Write a script that displays the following triangle patterns. Use for loops to generate the patterns.

*
**
***
****
*****
******
*******
********
*********
**********

Hint: Try to use nested loops and use the outer loop to display each row while the inner loop to display each column

for row in range(__,__):
    for column in range(__,__):
        print('*', end='')
    print()

2.3 Importing Modules

All Python programs can call a basic set of functions called built-in functions, including the print(), input(), len() and range() functions you’ve seen before. Python also comes with a set of modules called the standard library. Each module is a Python program that contains a related group of functions that can be embedded in your programs. For example, the math module has mathematics-related functions. The random module has random number-related functions, and so on.

Before you can use the functions in a module, you must import the module with an import statement. In code, an import statement consists of the following:

  • The import keyword
  • The name of the module
  • Optionally, more module names, as long as they are separated by commas

Once you import a module, you can use all the cool functions of that module. Let’s give it a try with the random module, which will give us access to the random.randint() function.

import random
for i in range(5):
    print(random.randint(1, 10))

You can view the execution of this program at https://autbor.com/printrandom/. The random.randint() function call evaluates to a random integer value between the two integers that you pass it. Since randint() is in the random module, you must first type random. in front of the function name to tell Python to look for this function inside the random module. We will discuss it more in the following chapter.

Check out the Python standard library here or here

2.3.1 Ending a Program Early with the sys.exit() Function

The last flow control concept to cover is how to terminate the program. Programs always terminate if the program execution reaches the bottom of the instructions. However, you can cause the program to terminate, or exit, before the last instruction by calling the sys.exit() function. Since this function is in the sys module, you have to import sys before your program can use it.

%%writefile exit.py

import sys

while True:
    print('Type exit to exit.')
    response = input()
    if response == 'exit':
        sys.exit()
    print('You typed ' + response + '.')
print('This line will not be printed')
%run exit.py

By using expressions that evaluate to True or False (also called conditions), you can write programs that make decisions on what code to execute and what code to skip. You can also execute code over and over again in a loop while a certain condition evaluates to True. The break and continue statements are useful if you need to exit a loop or jump back to the loop’s start. These flow control statements will let you write more intelligent programs. You can also use another type of flow control by writing your own functions, which is the topic of the next chapter.