Skip to content

Latest commit

 

History

History
339 lines (269 loc) · 14.6 KB

File metadata and controls

339 lines (269 loc) · 14.6 KB

Branching

So far, the Python programs we have written all run statements one by one from top to bottom. This kind of code structure is called the sequential structure. However, the sequential structure alone cannot solve all problems. For example, suppose we design a game. The condition for passing the first level is that the player gets 1000 points. After the first level ends, we need to decide, based on the player's score, whether the player enters the second level or whether we tell the player Game Over. In this kind of situation, our code will have two branches, and only one branch will be executed. There are many similar situations. We call this kind of structure a branching structure or selection structure. Give yourself one minute. You should be able to think of at least five similar examples.

Building Branches with if and else

In Python, the three keywords most often used to build branching structures are if, elif, and else. A keyword is a word with special meaning in the programming language, so clearly you cannot use it as a variable name. Of course, we do not use all three keywords every time we build a branching structure. Let us explain it with an example. Suppose we want to write a BMI calculator.

BMI, or Body Mass Index, is an internationally used indicator for measuring body shape and health. Its formula is:

$$ BMI = \frac{weight}{height^{2}} $$

It is usually considered normal when $\small{18.5 \le BMI < 24}$. If $\small{BMI < 18.5}$, the person is underweight. If $\small{BMI \ge 24}$, the person is overweight. If $\small{BMI \ge 27}$, the person is already in the obesity range.

Note: In the formula above, weight is measured in kilograms and height in meters.

"""
BMI calculator

Version: 1.0
Author: Luo Hao
"""
height = float(input('Height (cm): '))
weight = float(input('Weight (kg): '))
bmi = weight / (height / 100) ** 2
print(f'{bmi = :.1f}')
if 18.5 <= bmi < 24:
    print('Your body shape is great!')

Tip: The : at the end of the if line must be the normal ASCII colon typed with English input. The same is true for ', ", =, (, and ). We already reminded everyone of this before. Many beginners ignore this point, and then when they run the code they see a large pile of error messages. Of course, if you read the error messages carefully, it is still easy to find the problem, but it is strongly recommended that you switch to English input when writing code. This can avoid a lot of unnecessary trouble.

In the code above, after calculating and printing BMI, we added a branching structure. If $\small{18.5 \le BMI &lt; 24}$ is true, the program outputs Your body shape is great!, but if the condition is not satisfied, this output does not appear. This is what we mentioned just now: code can have different execution paths, and some code may not be executed at all. After the if keyword, we wrote the expression 18.5 <= bmi < 24. We said before that comparison operations produce Boolean values. If the Boolean value after if is True, then the line print('Your body shape is great!') below the if statement, which is indented by four spaces, will be executed.

Sample inputs:

First input:

Height (cm): 175
Weight (kg): 68
bmi = 22.2
Your body shape is great!

Second input:

Height (cm): 175
Weight (kg): 95
bmi = 31.0

Third input:

Height (cm): 175
Weight (kg): 50
bmi = 16.3

Only the first group of input gives a BMI in the range from 18.5 to 24, so it triggers the if condition and outputs Your body shape is great!. It should be explained that, unlike C, C++, Java, and other programming languages, Python does not use braces to build code blocks. Instead, it uses indentation to show the structure of code. If several statements need to be executed when the if condition is true, you only need to keep them at the same indentation. In other words, if several continuous lines of statements have the same indentation, then they belong to the same code block, and they can be treated as one whole when the code runs. Indentation can use any number of spaces, but 4 spaces are usually used. It is strongly recommended that you do not use the Tab key to indent code. If you are already used to doing that, you can set your code editor to automatically turn one Tab into four spaces. Many code editors support this, and PyCharm is set this way by default.

There is one more point. In programming languages such as C, C++, and Java, 18.5 <= bmi < 24 has to be written as two conditions, bmi >= 18.5 and bmi < 24, and then the two conditions are connected with the logical and operator. Python can also do that, so the previous if statement could also be written as if bmi >= 18.5 and bmi < 24:. But there is no need. Is not if 18.5 <= bmi < 24: nicer? The Java code below does the same thing. It does not matter if you cannot read Java code. Just feel the difference between it and Python syntax.

import java.util.Scanner;

class Test {

    public static void main(String[] args) {
        try (Scanner sc = new Scanner(System.in)) {
            System.out.print("Height(cm): ");
            double height = sc.nextDouble();
            System.out.print("Weight(kg): ");
            double weight = sc.nextDouble();
            double bmi = weight / Math.pow(height / 100, 2);
            System.out.printf("bmi = %.1f\n", bmi);
            if (bmi >= 18.5 && bmi < 24) {
                System.out.println("Your body shape is great!");
            }
        }
    }
}

Note: The code above is the Java version of BMI Calculator 1.0. There are good reasons why many people like Python. Usually it can solve the same problem with less code.

Next, let us make a small change to the code above. When BMI does not satisfy $\small{18.5 \le BMI &lt; 24}$, we also give a corresponding prompt message. We can add an else block after the if block. It will be executed when the condition given by the if statement is not satisfied. Clearly, only one of print('Your body shape is great!') under if and print('Your body shape is not standard enough.') under else will be executed.

"""
BMI calculator

Version: 1.1
Author: Luo Hao
"""
height = float(input('Height (cm): '))
weight = float(input('Weight (kg): '))
bmi = weight / (height / 100) ** 2
print(f'{bmi = :.1f}')
if 18.5 <= bmi < 24:
    print('Your body shape is great!')
else:
    print('Your body shape is not standard enough.')

If we want to give more exact prompt messages, we can modify the code above again and add more branches through the elif keyword, as shown below.

"""
BMI calculator

Version: 1.2
Author: Luo Hao
"""
height = float(input('Height (cm): '))
weight = float(input('Weight (kg): '))
bmi = weight / (height / 100) ** 2
print(f'{bmi = :.1f}')
if bmi < 18.5:
    print('You are underweight!')
elif bmi < 24:
    print('Your body shape is great!')
elif bmi < 27:
    print('You are overweight!')
elif bmi < 30:
    print('You are mildly obese!')
elif bmi < 35:
    print('You are moderately obese!')
else:
    print('You are severely obese!')

Let us use the same three groups of data again to test the code above and see what results we get.

First input:

Height (cm): 175
Weight (kg): 68
bmi = 22.2
Your body shape is great!

Second input:

Height (cm): 175
Weight (kg): 95
bmi = 31.0
You are moderately obese!

Third input:

Height (cm): 175
Weight (kg): 50
bmi = 16.3
You are underweight!

Building Branches with match and case

Python 3.10 added a new way to build branching structures. By using the match and case keywords, we can easily build multi-branch structures. When the official Python documentation introduced this new syntax, it used an example about HTTP response status codes, which is quite interesting. If you do not know what an HTTP response status code is, you can look at the documentation on MDN. Below we make a small change to the example in the official documentation to explain this syntax. First, look at the code implemented with the if-else structure below.

status_code = int(input('Status code: '))
if status_code == 400:
    description = 'Bad Request'
elif status_code == 401:
    description = 'Unauthorized'
elif status_code == 403:
    description = 'Forbidden'
elif status_code == 404:
    description = 'Not Found'
elif status_code == 405:
    description = 'Method Not Allowed'
elif status_code == 418:
    description = 'I am a teapot'
elif status_code == 429:
    description = 'Too many requests'
else:
    description = 'Unknown status code'
print('Description:', description)

Running result:

Status code: 403
Description: Forbidden

Below is the code implemented with match-case. Although it does exactly the same thing, the code looks simpler and more elegant.

status_code = int(input('Status code: '))
match status_code:
    case 400: description = 'Bad Request'
    case 401: description = 'Unauthorized'
    case 403: description = 'Forbidden'
    case 404: description = 'Not Found'
    case 405: description = 'Method Not Allowed'
    case 418: description = 'I am a teapot'
    case 429: description = 'Too many requests'
    case _: description = 'Unknown status code'
print('Description:', description)

Note: The case statement with _ works like a wildcard. If the previous branches do not match, the code will come to case _. case _ is optional. Not every branching structure needs a wildcard option. If case _ appears in a branching structure, it can only be placed at the very end. If there are other branches after it, those branches will be unreachable.

Of course, match-case has many advanced ways to use it. One of them is merged patterns, and we can learn that one first. For example, if we want to put status codes 401, 403, and 404 into one branch, and put 400 and 405 into one branch, while keeping the others unchanged, the code can also be written like this.

status_code = int(input('Status code: '))
match status_code:
    case 400 | 405: description = 'Invalid Request'
    case 401 | 403 | 404: description = 'Not Allowed'
    case 418: description = 'I am a teapot'
    case 429: description = 'Too many requests'
    case _: description = 'Unknown status code'
print('Description:', description)

Running result:

Status code: 403
Description: Not Allowed

Applications of Branching

Example 1: Piecewise Function Evaluation

Given the piecewise function below, enter x and compute y.

$$ y = \begin{cases} 3x - 5, & (x \gt 1) \\ x + 2, & (-1 \le x \le 1) \\ 5x + 3, & (x \lt -1) \end{cases} $$

"""
Evaluate a piecewise function

Version: 1.0
Author: Luo Hao
"""
x = float(input('x = '))
if x > 1:
    y = 3 * x - 5
elif x >= -1:
    y = x + 2
else:
    y = 5 * x + 3
print(f'{y = }')

According to actual development needs, branching structures can be nested. In other words, inside the if, elif, or else code block of one branching structure, we can introduce another branching structure again. For example, if the if condition being true means the player passes the level, but after passing the level we still need to evaluate the player's performance according to how many treasures or items they got, such as lighting one, two, or three stars, then we need to build a new branching structure inside the if. In the same way, we can also build new branches in elif and else. We call this a nested branching structure. Following this idea, the piecewise-function example above can also be implemented with the code below.

"""
Evaluate a piecewise function

Version: 1.1
Author: Luo Hao
"""
x = float(input('x = '))
if x > 1:
    y = 3 * x - 5
else:
    if x >= -1:
        y = x + 2
    else:
        y = 5 * x + 3
print(f'{y = }')

Note: You can judge for yourself which of the two styles above is better. In The Zen of Python, there is a sentence: Flat is better than nested. Flat code is considered better because if the nesting becomes too deep, readability is seriously affected. So I personally recommend the first style.

Example 2: Convert a Numerical Score to a Letter Grade

If the input score is above 90, including 90, output A; if the score is between 80 and 90, excluding 90, output B; if the score is between 70 and 80, excluding 80, output C; if the score is between 60 and 70, excluding 70, output D; if the score is below 60, output E.

"""
Convert a numerical score to a letter grade

Version: 1.0
Author: Luo Hao
"""
score = float(input('Enter the score: '))
if score >= 90:
    grade = 'A'
elif score >= 80:
    grade = 'B'
elif score >= 70:
    grade = 'C'
elif score >= 60:
    grade = 'D'
else:
    grade = 'E'
print(f'{grade = }')

Example 3: Calculate the Perimeter and Area of a Triangle

Enter the lengths of three sides. If they can form a triangle, calculate the perimeter and area; otherwise, print a message saying that a triangle cannot be formed.

"""
Calculate the perimeter and area of a triangle

Version: 1.0
Author: Luo Hao
"""
a = float(input('a = '))
b = float(input('b = '))
c = float(input('c = '))
if a + b > c and a + c > b and b + c > a:
    perimeter = a + b + c
    print(f'Perimeter: {perimeter}')
    s = perimeter / 2
    area = (s * (s - a) * (s - b) * (s - c)) ** 0.5
    print(f'Area: {area}')
else:
    print('A triangle cannot be formed')

Note: The if condition above means that the sum of any two sides is greater than the third side. This is the necessary condition for forming a triangle. When this condition is satisfied, we need to calculate and output the perimeter and area, so the five statements under if all keep the same indentation. They are one whole, and as long as the if condition is satisfied, they will all be executed. This is the concept of a code block that we mentioned earlier. In addition, the formula used above to calculate the area of a triangle is called Heron's formula. Suppose there is a triangle whose side lengths are $\small{a}$, $\small{b}$, and $\small{c}$, then the area of the triangle $\small{A}$ can be obtained by the formula $\small{A = \sqrt{s(s-a)(s-b)(s-c)}}$, where $\small{s=\frac{a + b + c}{2}}$ means the semiperimeter.

Summary

After learning branching structures and loop structures in Python, we can solve many practical problems. I believe this lesson has already helped everyone master how to build branching structures. In the next lesson, we will introduce loop structures. After learning these two lessons, you will definitely find that you can write a lot of very interesting code. Keep going.