Introduction to Python Programming - Control Flow
Tags: python, beginners, tutorial, programming
Published: 2022-10-06 05:39:46

At some point, while writing a program, you would need to make decisions either based on your business logic or based on user input from a client such as a shell or a webpage. Also, you may want some parts of your program to run repeatedly. This article shows you how you can control the flow of your program in Python.

## Table of Contents

- [Conditions](#conditions)
  - [If-Elif-Else Statements](#if)
  - [Nested If Statements](#nested-ifs)
  - [If-Else Expression](#if-ex)
  - [match statement](#match-statement)
- [Loops](#loops)
  - [For Loop](#for)
  - [While Loop](#while)
  - [Break and Continue Statements](#break-continue)
- [Pass statement](#pass-statement)
- [Try-Except Statements](#try-except)

## Conditions
<a id="conditions"></a>

### If-Elif-Else Statements
<a id="if"></a>

Use an `if` or `if-elif-else` statement when you want to perform an operation or logic based on some conditions. The overall format is:

    # Do not run this!
    # It's just for illustration

    if condition1:
        # Run if the condition is true, avoid the others if they specified
    elif condition2:
        # Run here if condition1 is false and condition2 is true
    else:
        # Do something else

> Note that in Python, indentation matters. In the above statement, there are three blocks or indents - The `if`,  `elif`, and the `else` blocks.
> Among the three, only the `if` block is required. The `elif` and `else` parts are optional.

Let's say we run a restaurant that only allows people 18 years and above. We may set a variable called `age_allowed` to the number 18. Then we check if the customer's age matches our expectations. Let's set three variables associated with age. Also, add two `string` variables as messages to the customers.

```python
# The allowed age
allowed_age = 18

# Age of the first customer
age_1 = 57

# Age of the second customer
age_2 = 17

# Some message to the customer depending on our criterium
not_ok_message = "You are not allowed to enter!"
ok_message = "Welcome to the DELISH haven!"
```

We do the tests:

```python
# True: prints the ok_message
if age_1 >= allowed_age:
    print(ok_message)


# False: does not print the ok_message
if age_2 >= threshold_age:
    print(ok_message)
```

Print an "okay message" if the customer's age is higher or equals the allowed age. We used two `if` statements or blocks, and that's fine. However, what if the test fails? We could use another `if` block or add an else block. For example:

```python
# True: prints the ok_message
if age_1 >= allowed_age:
    print(ok_message)
else:
    print(not_ok_message)

# False: prints the not_ok_message
if age_2 >= allowed_age:
    print(ok_message)
else:
    print(not_ok_message)
```

What if we have multiple conditions that are different? We test many conditions using `elif` blocks. Only the block whose condition passes executes. If available, an `else` block executes if all tests fail.

Let's say we give out separate seats to customers based on their age group. For customers between 18 and 27, we will give them the first-row seats, those between 28 and 37 will take the second-row seats, and so on. Let's assign a seat to a customer!

```python
# Yeah, a_customer
a_customer = 45

# I like laziness. Let's save typing
message = "Please take the {} seat"

if a_customer < 18:
    print("Sorry, our DELISH only allows customers 18 and above!")

# checks between 18 and 27
elif age <= 27:
    print(message.format("first"))

# checks between 28 and 37
elif age <= 37:
    print(message.format("second"))

# checks between 38 and 47
elif age <= 47:
    print(message.format("third"))

# 81 and above
else:
    print("Well, this part is not always necessary!")
```

> Wondering about the `message` variable in the above code block? Remember that Python has a string `format` function/method that lets you do something like this `"My name is {}, and I am {} years old".format("Peter Griffin", 90)`.

One last example, just for fun!

```python
# Reset age_1 and age_2

age_1 = 5
age_2 = 30

pro_footballer = True
```

```python
if (age_2 > 18) and pro_footballer:
    # runs
    print("Seems appropriate, maybe! I guess you deserve more credit!")
else:
    print("Dude? why not!")
```

```python
if (age_1 < 10) and pro_footballer:
    print("You are a prodigy! Have you seen the news?")
else:
    print("You probably read too much!")
```

### Nested If Statements

<a id="nested-ifs"></a>

An if statement (top-level) can contain other if statements (child-level). The child-level or contained if statements can contain other if statements, and so on. For example

    # Do not run this!
    # It's just for illustration
    if condition:
        # top level if block
        if another_conditon:
            # second-level if block
            if yet_another_condition:
                # you get the gist
            else:
                # definitely!
        else:
            # second-level else block
    else:
        # top/first-level else block

> Heads up! Use nested ifs wisely. Nesting too deep is terrible for eggs! Sorry :)

### If-Else Expression
<a id="if-ex"></a>

An `if-else expression` has the pattern `True if condition else False`. This expression is "give me the `True` part if the condition is true or, give me the `False` part". For example, chosen_age is `age_2` if we want a `pro_footballer` else it is `age_1`.

```python
chosen_age = age_2 if pro_footballer else age_1
```

```python
print("The chosen age is {} years old".format(chosen_age))
# The chosen age is 30 years old
```

### Match Statement
<a id="match-statement"></a>

You can use a match statement in place of an if-elif-else with multiple elif-blocks. The format is

    match an_expression:
        case option_1:
            # do something if an_expression equals/matches option_1
        case option_2:
            # do something if an_expression equals/matches option_2
        ...
        case option_n:
            # do something if an_expression equals/matches option_n
        case _:
            # do something if an_expression does not match any of the provided options

Only the code in the first block that matches the expression executes. In the case of no match, the default case block `case _` runs.

Let's say we have a list of fruits and would like to react to a customer's choice of the best fruit.

```python

best_fruit = 'oranges'

match best_fruit:
    case 'apples':
        print('nice fruit..but not as nice as...whatever!')
    case 'oranges':
        print('even better...Lorem ipsum...Don\'t worry')
    case 'mangoes':
        print('You made a great choice!')
    case 'banana':
        print('We are quite far from the trees...Might you pick something else?')
    case _:
        print('Don\'t know what this is...Try again?')

```

The code above will print `'even better...Lorem ipsum...Don't worry'` because `best_fruit` is oranges in the example.

If you want to react to multiple options, use the pipe (|) operator. For example

```python

food = 'rice'

match food:
    case 'rice' | 'potatoes' | 'corn':
        print('We are rich in carbohydrates, and you can spend it!')
    case 'carrot' | 'cabbage' | 'lettuce':
        print('What a bunch of vegetables!')
    case _:
        print('Probably an Aliens\' diet!')

```

If a user selects any of *rice* **or** *potatoes* **or** *corn* then `'We are rich in carbohydrates, and you can spend it!'` is printed. Conversely, the same code runs if the user chooses carrot, cabbage, or lettuce.



## Loops

<a id="loops"></a>

Using loops, we can repeat specific parts of our code. Or we can go through sequences or dictionaries one item at a time. : The `for` and the `while` loops are types of loops in Python.

### For Loops
<a id="for"></a>
The `for` statement allows us to go through the elements of a collection (such as list, tuples, dictionary, string) one after the other (iteration). It follows the following pattern:

    for element in collection:
        # Do something with the element
        
The `element` variable represents each item in the collection during iteration. **Note that the `element` can take any name.** Let's see some examples.

We start by creating four variables, `my_list`, a list of numbers. A list containing tuples `list_of_tuples`, `menu` a dictionary, and `name` a string.

```python

my_list = [1, 2, 3, 4, 5]

list_of_tuples = [(1, 2), (3, 4), (9, 10), (11, 12)]

menu = { "rice": 45, "apples": 33, "garlic": 20, "pepper": 10 }

name = "John Doe"
```

Let's print two statements using the `my_list` elements.

```python
for num in my_list:
    print("The number is {}".format(num))
    print(f"num times 2 is {num * 2}\n") # notice the \n
```

    The number is 1
    num times 2 is 2
    
    The number is 2
    num times 2 is 4
    
    The number is 3
    num times 2 is 6
    
    The number is 4
    num times 2 is 8
    
    The number is 5
    num times 2 is 10
    
    

>`\n` is called a newline character. The pattern `f"{num}"` is equivalent to `"{}".format(num)`.

Using **tuple unpacking**, we can retrieve the elements of the tuple in the list within the iteration.

```python
for first, second in list_of_tuples:
    print(f"First is {first}, second is {second}")
```

    First is 1, second is 2
    First is 3, second is 4
    First is 9, second is 10
    First is 11, second is 12

> First run: `first, second` = (1, 2). Second run: `first, second = (3, 4)`. Third run: `first, second = (9, 10)`. Fourth run: `first, second = (11, 12)`.

We get a series of letters when we loop through a string. For example:

```python
for letter in name:
    print(letter)
```

    J
    o
    h
    n
     
    D
    o
    e

#### Looping Through a Dictionary

Iterating through a dictionary is not so straightforward. We can loop through the dictionary keys using the `keys()` method and through the values using the `values()` method, or both (`items()`).

```python
# Loop through the keys only
for key in menu.keys():
    print(key)
```

    rice
    apples
    garlic
    pepper
    
Omitting the `keys()` method yields the same result.

```python
# Same as above
for key in menu:
    print(key)
```

    rice
    apples
    garlic
    pepper
    
Use the `values()` method to retrieve only the values:

```python
# Loop through the values only
for value in menu.values():
    print(value)
```

    45
    33
    20
    10
    
Use the `items()` method to retrieve the keys and values!

```python
# loop through the keys and values
for key, value in menu.items():
    print("{}: {}".format(key, value))
```

    rice: 45
    apples: 33
    garlic: 20
    pepper: 10
    

### While Loop
<a id="while"></a>

The template is:

    while condition_is_true:
        # Keep doing whatever we put here


Let's say we want to print out some numbers 1 to 5. We could set a `count` variable and increment it within a loop.

```python
count = 1

while count <= 5:
    print(count)
    count += 1  # increment the count
```

    1
    2
    3
    4
    5
    
> To avoid an **infinite** loop, the while condition must be evaluated as `False` at some point. We increment the count variable `count += 1` to ensure that the count becomes greater than five eventually.

>Operators like `+= -= \= *=` allows us to perform arithmetics and assignment in a single step. For example,
`a = a + 1` can be written as `a += 1`. So also `a = a * 7` can be replaced with `a *= 7` and so on.

> Note that just like the if statement, loops can be nested.

Give me all even numbers between 1 and 20:

```py
# We're starting from zero
count = 0

while count <= 20:
    if count % 2 == 0:
        print(count)
    count += 1  # increment the count
```

    0
    2
    4
    6
    8
    10
    12
    14
    16
    18
    20


### Break and Continue Statements
<a id="break-continue"></a>

The `break` statement helps us control a loop's termination. The `continue` statement skips an iteration step.

In the example below, we want to print the multiples of 5, specifically from 5 to 20. We set the counter to `5` and then increment by `5`. When the counter becomes `20`, we exit the while loop using a `break` statement.


```python
counter = 5

while True:
    print(f'counter is {counter}')
    if counter == 20:
        print("**** stopping here ****")
        break
    counter += 5
```

    counter is 5
    counter is 10
    counter is 15
    counter is 20
    **** stopping here ****
    
To demonstrate the `continue` statement, create a `numbers` list like the one below. 

```py
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
```

If we want the odd numbers between 1 and 11, we will write:

```python

for n in numbers:
    if n % 2 == 0:
        continue # skip even numbers
    print(n)
    if n == 11:
        break  # stop at 11
```

    1
    3
    5
    7
    9
    11
    

In the code above, we skipped the **even numbers** with `continue` and then exited with `break` when the current number `n` was `11`,

> How do I choose between a `for` and a `while` loop? It largely depends on the situation. If you're dealing with a collection, a for loop is preferable most of the time. In other cases, consider a `while loop`.

## Pass Statement

Like comments (`#`), the `pass` statement tells Python to ignore parts of a program. However, the `pass` statement is excellent for ignoring code blocks. This code block may be if-elif-else, a loop block, or a function or class block. For example:


```python

# I'm still thinking of what to do
# So I'll just use a pass so Python won't complain
num_years = 45

if num_years > 80:
    pass
else:
    pass


# I'm not ready to work with num
for num in [1, 2, 3, 4, 5]:
    pass

```

## Try-Except Statement
<a id="try-except"></a>

The try-except statement enables us to perform an alternative action if the intended action fails. For example, we may want to open a file, convert a string to an integer, and so on. These attempts might fail, resulting in an error that may crash our program. The try-except statement solves this problem. The format is:

    try:
        # Do something that may fail
    except:
        # Do something else. For example, handle the error and inform the user of your program
        
        
The example below demonstrates the many uses of `try-except`. Converting from integers may produce errors. To guarantee the continuation, use a try-except statement.


```python
bad_integer_string = "aa12r"

good_integer_string = "12345"
```


```python
try:
    good_integer = int(good_integer_string)
    print("Worked! The number is", good_integer)
except:
    print("Failed")
```

    Worked! The number is 12345
    


```python
try:
    bad_integer = int(bad_integer_string)
    print("Worked??? The number is", bad_integer)
except:
    print("Failed!!!")
```

    Failed!!!

## Conclusion

In this article, we looked at controlling program execution with if-elif-statements statements, match statements, for and while loops, pass statements, and so on. Next, we will write some programs. Thanks for reading!