4. Control flow (if & while)#

Until now, we have worked with simple programs where the execution flow is sequential—one instruction follows another. To develop more complex programs, we need to introduce control structures (see glossary Control Structures). We start with conditional branching using the if statement and then move on to loops like while. Later, we will also cover a third control structure, the “for each” loop.

4.1. The if Statement#

The if statement allows us to execute a block of code only if a specified condition is True. It provides a way to make decisions within our programs. Here’s a simple example of calculating the absolute value of a number using an if statement.

def abs(x):
    if x < 0:
        x = -x
    return x

print(abs(10))    # print 10
print(abs(-10))   # print 10

In this example, if the value of the parameter xis negative, then it is reverse. Thus, the returned value of the function is always positive.

Consider a more elaborate example where the program determines if a user is eligible to vote based on their age. The user inputs their age, and the program displays a personalized message.

age = int(input('Enter your age: '))

if age < 18:
    print('You cannot vote.')
elif age > 18:
    print('You can vote.')
else:
    print('You can vote. Bravo, it must be your first time!')

In this case, the program uses the if, elif, and else statements to handle different age ranges. It first checks if the user is younger than 18, then if they are older than 18, and finally handles all remaining case (the age is exactly 18).

4.1.1. General Form of the if Statement#

The general structure of an if statement in Python is as follows:

if condition_1:
    instructions_1
elif condition_2:
    instructions_2
elif condition_3:
    instructions_3
...
else:
    instructions_else

Here are some important points to note:

  • Conditions. They are boolean expressions.

  • Indentation. Instructions within each block are indented, typically by one tab or four spaces. This indentation indicates which statements belong to which condition.

  • Optional Clauses. While the if clause is mandatory, the elif and else clauses are optional. You can use as many elif clauses as needed, or omit them entirely if they are not required. The else block is executed if none of the preceding conditions are met and is always placed at the end.

  • Nesting. It is possible to nest if statements inside each other. While nesting can sometimes be useful, it is often clearer and more concise to use elif to handle multiple conditions. Here is an example of both nested if statements and an equivalent version using elif.

# Nested if statements
x = int(input("Enter a number: "))
if x < 0:
    print("x is negative")
else:
    if x > 0:
        print("x is positive")
    else:
        print("x is zero")
# Using elif
x = int(input("Enter a number: "))
if x < 0:
    print("x is negative")
elif x > 0:
    print("x is positive")
else:
    print("x is zero")

4.1.2. The pass Statement#

In some situations, it may be necessary to include a branch for completeness, even if it doesn’t perform any actions. In such cases, the pass statement can be used (see glossary Pass). It is a placeholder that indicates “do nothing” but maintains proper syntax (remember that a block of code is defined by its indentation, thus you need at least one instruction even if it does nothing).

def abs(x):
    if x >= 0:
        pass
    else:
        x = -x
    return x

4.2. The while Loop#

The while loop (see glossary While) is a fundamental control structure in programming that allows for the repeated execution of a block of code as long as a specified condition remains True. This construct is particularly useful when the number of iterations required is not known beforehand and depends on the dynamic state of the program. Consider the following example that calculates the integer part of the square root of a number input by the user.


def int_sqrt(x):
    i = 0
    while (i + 1) * (i + 1) <= x:
        i += 1
    return i

print(int_sqrt(27))      # print 5

In this code, the while loop continues to increment i as long as the square of (i + 1) is less than or equal to the parameter x. Once the condition is no longer satisfied, the loop exits, and the return value is set.

4.2.1. General Form#

The general syntax of a while loop is as follows:

while condition:
    instructions

The loop begins with the while keyword, followed by a condition. If this condition evaluates to True, the block of code indented under the while statement is executed. This process repeats until the condition evaluates to False. Here is another example demonstrating a while loop used to validate user input.

def read_value():
    print("Please enter a value between 0 and 100 (inclusive)")
    v = -1
    while v < 0 or v > 100:
        v = int(input("Your value? "))
    return v

s = read_value()
print("The entered value is correct.")
print(s)

In this function, read_value, the while loop ensures that the user inputs a value within the specified range. The loop continues prompting the user until a valid value is provided.

4.2.2. Infinite Loops#

The while loops must be used with caution to avoid infinite loops, which occur when the loop’s condition never becomes False. For example, consider the task of calculating the base-10 logarithm of an integer. An integer logarithm can be determined by counting the number of times a number can be divided by 10 before it becomes zero. Fore instance, with the number 127.

127 // 10 = 12
12 // 10 = 1
1 // 10 = 0

After three divisions, the number becomes zero, so the logarithm is 3.

Here is a function implementing this approach:

def log10(x):
    i = 0
    while x != 0:
        x = x // 10
        i += 1
    return i

x = int(input("Enter an integer: "))
l = log10(x)
print(l)

However, this implementation does not handle negative numbers properly and will result in an infinite loop if x is negative. To address this, consider the following corrected version that excludes negative numbers.

def log10(x):
    i = 0
    while x > 0:
        x = x // 10
        i += 1
    return i

x = int(input("Enter an integer: "))
l = log10(x)
print(l)

Alternatively, to handle negative values more gracefully, you might return None when encountering negative inputs.

def log10(x):
    if x < 0:
        return None

    i = 0
    while x > 0:
        x = x // 10
        i += 1
    return i

x = int(input("Enter an integer: "))
l = log10(x)
print(l)

4.2.3. Skipping an iteration#

Sometimes, it is necessary to skip the rest of an iteration and go back to the condition. This can be achieved using the continue statement (see Continue), which immediately returns at the beginning of the while loop.

x = 1
while x < 10:
    if x % 2 == 0:
        continue

    print(x)

4.2.4. Exiting a Loop Prematurely#

Sometimes, it is necessary to exit a loop before its condition becomes False. This can be achieved using the break statement (see glossary Break), which immediately terminates the loop’s execution and proceeds with the code following the loop.

Consider the following example that uses break to exit a loop with an always-true condition:

x = 1
while True:
    print(x)
    x += 1
    if x % 5 == 0:
        break

print(".")

In this code, the while loop will run indefinitely until the break statement is executed when x is divisible by 5. The loop prints numbers incrementally and exits once the condition is met.