3. Decisions (UNDER CONSTRUCTION)

Chapter 0011 2

Stop

Unfinished Chapter!!

I am actively working to complete this eBook, and I haven’t gotten to this chapter yet. In fact, it’s probably just a copy/paste from a similar chapter in my C# book.

In other words, don’t read this yet!

What’s the Point?

Source code examples from this chapter and associated videos are available on GitHub.


Decisions, or branching gives our programs the ability to execute different code depending on what’s happening as it runs. At the core of decisions is the concept of Boolean logic, which is named after a 19th-century mathematician named George Boole. Boolean logic is the foundation of the if statements that will allow our programs to branch.

3.1. Boolean Expressions

Until now, our programs have all executed very sequentially and predictably—one line of code after another. How boring! To give our programs the ability to branch and execute different code based on different conditions, we need to introduce the concept of decisions.

In computer programming, a decision is made based on a Boolean expression, which is an expression that evaluates to either True or False. Think of Boolean expressions as questions that can be answered with a simple "yes" or "no". Is this student’s GPA high enough to qualify for the scholarship? Has this cell phone customer used all of their data? Did the user type "exit"?

The True or False value of a Boolean expression can be used to determine which code block will execute next, so it’s important to understand how they work.

Time To Watch!

Boolean Logic in Python [COMING SOON!!!]

3.1.1. Boolean Values

The simplest way to use Boolean in Python is with the keywords True and False. These can be assigned to variables of type bool (which is technically a subtype of int, but we won’t worry about that right now):

Example 3.1 - Declaring and assigning Boolean variables in Python.
1
2
isTimAmazing = True
isClassBoring = False

3.1.2. Comparison Operations

Also known as _relational operations, comparison operations are expressions that compare two values. You’ll remember them from math class. Is x greater than y? Is a less than or equal to 10? Is c equal to d? Comparison operators, like arithmetic operators, are binary operators that require two operands. In other words, we need two values to compare. In our math class, we could draw symbols that aren’t on our keyboard, like a ≥ for "greater than or equal to." In Python, where we have to stick with stuff on our keyboard, we use the following symbols:

Table 1. Python comparison operators
Operator Description

==

Equality (checks if two values are equal)

!=

Inequality (checks if two values are not equal)

<

Less-than

>

Greater-than

<=

Less-than-or-equal-to

>=

Greater-than-or-equal-to

A comparison operation will always evaluate to either True or False. We can store that result in a bool variable, as shown below, and we’ll also learn how to use these expressions in if statements later in this chapter.

Example 3.2 - Using comparison operators in Python
1
2
3
canBuyAlcohol = age >= 21
isNegative = number < 0
isArethaFranklin = name == "Aretha Franklin" (1)
1 This statement uses the == operator to check if two strings are equal.

These assignment statements work like any other: the expression to the right of the equals symbol is evaluated, and the result is stored in the variable on the left.

3.1.3. Checking str Equality

In Python, we can test string equality with the == operator. This is different from Java, where we can’t use the == operator on String values. I mention it here because it’s a potential source of confusion for students who are learning both languages at the same time, or who are coming to Python with Java experience.

The == operation is case sensitive, so Aretha Franklin is different from aretha franklin. To perform a case-insensitive comparison, we can use the casefold() method.

Example 3.3 - Case insensitive string comparison in Python
1
2
3
name = "aretha franklin"

isArethaFranklin3 = name.casefold() == "aretha franklin".casefold()

Programmers with experiences in other languages may be familiar with string comparisons by converting to all uppercase or lowercase. Though the above approach using casefold() is preferred, you could use the upper() or lower() methods to perform a case-insensitive comparison.

Example 3.4 - Case insensitive string comparison in Python
1
2
3
name = "aretha franklin"

isArethaFranklin4 = name.upper() == "ARETHA FRANKLIN"

3.2. if Statements

The if statement is the basic decision-making structure in Python. It allows us to execute a block of code only if a specified condition is True.

The syntax of an if statement is the keyword if, followed by a Boolean expression, followed by a colon and an indented block of code. If the Boolean expression evaluates to True, the block of code will execute. If the Boolean expression evaluates to False, the block of code will be skipped. In either case the program will continue executing the next line of code after the if-block.

Example 3.5 - A basic if statement in Python.
1
2
3
4
cash = int(input("How much money do you have? "))
if cash < 15:
    print("Check the bargain bin.") (1)
print("Hope you find something you like!")
1 The indentation is important—that’s how Python knows which lines of code belong to the if block.

In this example, the if statement checks if the variable cash is less than 15. if the input is less than 15, the Boolean expression evaluates to True, and the block of code inside the if statement (line 3) is executed—and it prints Check the bargain bin." The program then continues to the next line of code, which prints Hope you find something you like!

So, the output of the above program, if the user enters 14, is:

Check the bargain bin.
Hope you find something you like!

If the user enters 22, the Boolean expression would evaluate to False, and the block of code inside the if statement would be skipped. The program would then continue to the next line of code, which prints Hope you find something you like! Line 5 will execute every time the program runs, regardless of the value of cash.

Keep in mind, the if statement can contain any Boolean expression—not just this simple example.

3.3. Adding an else Block

An if statement simply determines whether or not to execute a single block of code. If we want to choose between two blocks of code, we can add an else block to the if statement. The syntax is straightforward: after the if block, add the keyword else and a colon, followed by a block of indented code.

Example 3.6 - An if-else statement in Python.
1
2
3
4
5
6
cash = int(input("How much money do you have? "))
if cash < 15:
    print("Check the bargain bin.")
else:
    print("You can probably afford a new release.")
print("Hope you find something you like!")

An if-else statement will always execute one block of code or the other, but never both. Basically, it’s an either-or situation.

Time To Watch!

if and if-else Statements in Python [COMING SOON!!!]

Interesting!

Python includes a shorthand form of an if-else statement called the ternary operation, which allows for concise (one-line) if-else statements. It’s a useful little trick, but it can be confusing for beginners—and for the people reading our code later. We won’t look at ternary operators in this course, but a web search should turn up plenty of examples if you are curious.

Assignments in my course require you to use complete if-else statements with indented blocks, so you shouldn’t use a ternary operation in code you submit to me.

3.4. The elif Keyword

The basic if-else structure is great for choosing between two blocks of code, but what if we have more than two options? To handle this, we can use the keyword elif, which is short for else if. elif basically means "if the last condition was False, then try this one." If the previous condition was True, the elif block just gets skipped without even checking the condition in the elif statement.

Many other programming languages, such as Java and C#, don’t have an elif keyword, but instead chain together the keywords else if to accomplish the same thing.
Example 3.7 - Use of the elif keyword to select one option from many.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
track_num = int(input("Enter track number: "))

if track_num == 1:
    song_title = "What's Going On"
elif track_num == 2:
    song_title = "What's Happening Brother"
elif track_num == 3:
    song_title = "Flyin' High (In the Friendly Sky)"
elif track_num == 4:
    song_title = "Save the Children"
elif track_num == 5:
    song_title = "God Is Love"
elif track_num == 6:
    song_title = "Mercy Mercy Me (The Ecology)"
else:
    song_title = "not found"

print(f'Track #{track_num} on side one of "What\'s Going On" by Marvin Gaye is "{song_title}".') (1)
1 Note the use of an escape character (`) in the `print()` statement to allow for the single quote in What’s Going On without a syntax error.

In this example, the user inputs a track number and we use an if-elif structure to output the song’s title.

The code begins with the first statement, and if it evaluates to True, the corresponding block of code will execute—setting the song title to "What’s Going On". If the first statement evaluates to False, the program will move on to the next elif statement and check that condition, and so on through all of the elif blocks. Once an expression evaluates to True and the corresponding code block is executed, the program will then jump to the first line of code after the end of the if-elif structure—the print() statement. Only one block of code can execute. If the program gets through the entire structure without finding a True condition, it will execute the block of code in the else block, if one is present; if there’s no else block, the program will just continue on to the next line of code after the if-elif structure.

As is often the case in programming, there are multiple ways to solve this problem. As we learn more (or if you have previous coding experience), you may find that you prefer a different way to write this code. That’s great, and is part of the fun of coding. But keep in mind that your instructor’s job is to assess your understanding of the concepts being taught. You can’t get points on an if-elif assignment if you don’t use an if-elif structure!

In summary, an if-elif structure can execute, at most, one block of code. If an else block is included at the end, it guarantees that exactly one block of code will execute.

Time To Watch!

elif Statements in Python [COMING SOON!!!]

Files from video:

Take It for a Spin

This is a good time to stop and try out what you’ve learned so far. The Coding Practice assignment for this chapter can be completed with the concepts covered to this point.

3.5. Nested if Statements

If we want a block of code to execute only if two different conditions are met, we can place if statements inside of each other, which is called nesting. Nested if statements check multiple conditions in a hierarchical way: if one condition is met, it will proceed and check the next condition; if the first condition is not met, it will skip the inner if block.

This is not a special structure or keyword in Python, it’s just a useful way to help beginners understand how and when this way of organizing if-else and/or if-elif statements is useful.
Example 3.8 - Basic structure of a nested if-else statement.
1
2
3
4
5
6
7
if condition1:
    if condition2:
        # executes if both condition1 and condition2 are True
    else:
        # executes if condition1 is True and condition2 is False
else:
    # executes if condition1 is False

In the example below, the outermost if-else structure checks the side number of the album. The if-else structures within those blocks check the track number and return the appropriate song title.

Example 3.9 - Use of nested if-else statements to select one option from many.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
side_num = int(input("Enter side number: "))

track_num = int(input("Enter track number: "))

if side_num == 1:
    if track_num == 1:
        song_title = "What's Going On"
    elif track_num == 2:
        song_title = "What's Happening Brother"
    elif track_num == 3:
        song_title = "Flyin' High (In the Friendly Sky)"
    elif track_num == 4:
        song_title = "Save the Children"
    elif track_num == 5:
        song_title = "God Is Love"
    elif track_num == 6:
        song_title = "Mercy Mercy Me (The Ecology)"
    else:
        song_title = "not found"
elif side_num == 2:
    if track_num == 1:
        song_title = "Right On"
    elif track_num == 2:
        song_title = "Wholy Holy"
    elif track_num == 3:
        song_title = "Inner City Blues (Make Me Wanna Holler)"
    else:
        song_title = "not found"
else:
    song_title = "not found"

print(f'Track #{track_num} on side {side_num} of "What\'s Going On" by Marvin Gaye is "{song_title}".')

Time To Watch!

Nested if-else Statements in Python [COMING SOON!!!]

Files from video:

3.6. Using Logical Operators

In addition to the comparison operators, Python also has three logical operators we can use to make more complex Boolean expressions. Two of the logical operators are binary, so they take two operands—but the operands are Boolean expressions or values instead of numbers. The third logical operator is unary, meaning it only takes one operand—which is also a Boolean expression or value.

Table 2. Python logical operators
Operator Name Description

and

Logical AND

Evaluates to True if both operands are True

or

Logical OR

Evaluates to True if either operand is True

not

Logical NOT

Evaluates to True if the operand is False; evaluates to False if the operand is True

These operators can be used to combine multiple Boolean expressions into a single, more complex expression. For example, we could check if a student is eligible for a scholarship based on both their GPA (3.5 or better) and their age (younger than 25).

Example 3.10 - A decision using a logical AND operation in Python.
1
2
if day.casefold() == "Tuesday" and age > 55:
    print("You qualify for the Tuesday afternoon Senior Discount!")

In this example, the and operator is used to combine two Boolean expressions. The if statement will only execute the block of code if both expressions are True.

Often, the logic we create using an AND operation can be implemented using nested if-else statements, and vice versa.

The OR operation is similar to AND, but only one of the expressions needs to be True for the entire expression to be True.

Example 3.11 - A decision using a logical OR operation in Python.
1
2
3
4
genre = input("Enter the album genre: ")

if genre.casefold() == "blues" or genre.casefold() == "r&b":
    print("Good choice. This album qualifies for a discount.")

3.6.1. The NOT Operator

The NOT operation is a little different, as it only takes one operand (making it a unary operator_ if you’re nerdy about words, like I am). It simply inverts the value of the operand. If the operand is True, the NOT operation will evaluate to False. If the operand is False, the NOT operation will evaluate to True.

Example 3.12 - A decision using a logical NOT operation in Python.
1
2
3
4
isBieberAmazing = False

if (not isBieberAmazing):
    print("At least his mom still loves him!")

3.6.2. Range Checking

There are a lot of situations where we might need to combine multiple conditions to make a decision, but one of the most common is range checking. Range checking means we want to see if a value is within a specified range, and is useful for things like categorizing data, validating user input, and enforcing rules or constraints on values.

A common example of range checking is to convert a percentage grade to a letter grade. A percentage between 80 and 99.9 would be a B, for example, while a percentage between 60 and 69.9 would be a D.

There are two ways to write range checks in Python. First, we can use logical AND operations to combine multiple comparisons:

if percentage >= 80 and percentage <90:

Or, we can chain together the comparisons without the and operator:

if 80 ⇐ percentage < 90:

This second way of writing essentially makes two comparisons: is percentage greater than or equal to 80, and is percentage less that 90.

Many programming languages don’t allow this second, more abbreviated way of writing range checks. In those languages we’d need to use AND operations.
Example 3.13 - Range checking using logical operators in Python.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
minutes = int(input("Enter album length in minutes: "))

if minutes < 10:
    print("This release is a single.")
elif 10 <= minutes <= 29:
    print("This release is an EP (Extended Play).")
elif 30 <= minutes <= 50:
    print("This release is an LP (Long Play).")
else:
    print("This is a double album or box set.")

3.7. switch Statements

Python includes a structure called a match statement that can be used to choose one code block from many options. It is essentially another way to write an if-elif structure, but it can be more readable and easier to write in some situations. I generally consider match structures to be optional—you can complete all of the assignments in this course without using them—but they are a useful tool to have in your programming toolbox. And since you see them often in code written by others, it’s good to know how they work.

Functionally, a match statement compares an expression’s (variable’s) value to a series of values (or patterns) of case blocks. The first value (or pattern) that matches gets executed, and the rest of the case blocks are skipped. \ If the match statement doesn’t find a match, it doesn’t execute any case blocks; however, we can choose to define a wildcard case block that will execute if no other match is found, similar to an else block at the end of an if-elif structure.

The basic syntax of a match statement is as follows:

Example 3.14 - A basic match statement in Python.
1
2
3
4
5
6
7
8
9
match expression:
    case value1:
        # Code to be executed if expression equals value1
    case value2:
        # Code to be executed if expression equals value2
    case value3:
        # Code to be executed if expression equals value3
    case _:
        # Code to be executed if expression doesn't match any case

The expression after the match keyword is evaluated, and then the program will move through the case statements one at a time until if finds a match for the value of the expression. If there is no match, the program will execute the block, if it is present; a default block is defined with the wildcard character _, which matches anything.

Example 3.15 - A switch statement in Python.
1
2
3
4
5
6
7
8
9
switch (lightColor)
    case "red":
        print("Stop! In the Name of Love!");
    case "yellow":
        print("Slow ride! Take it easy!");
    case "green":
        print("Go Johnny, go go!");
    case _:
        print("Invalid light color.");
Programmers coming to Python from other languages may be familiar with switch-case statements. From a beginner’s perspective, Python’s match statement serves the same purpose, but it’s matching is generally more flexible than the simple value matching of a switch-case statement, so they aren’t exactly the same thing. Don’t let this brief overview fool you—there are a lot of useful things you can do with match statements.

Check Yourself Before You Wreck Yourself (on the assignments)

Chapter Review Questions

Sample answers provided in the Liner Notes.