Flow control

“Would you tell me, please, which way I ought to go from here?”
“That depends a good deal on where you want to get to,” said the Cat.
“I don’t much care where—” said Alice.
“Then it doesn’t matter which way you go,” said the Cat.
“—so long as I get somewhere,” Alice added as an explanation.
“Oh, you’re sure to do that,” said the Cat, “if you only walk long enough.”

Alice’s Adventures in Wonderland

Up until now the code war rather… underwhelming. You only executed a sequence of commands each and every time. But with the introduction of the control flow of a program a whole new world of programs reveals itself. It is up to your experience and creativity to use the control flow tools to structure your code in a way that complex tasks can be handled.

Boolean expressions

Knowing boolean expressions is essential for the control flow of a program. Python handles this rather intuitively. The most important boolean operations are

==:equal to
!=:unequal to
<:less than
<=:less than or equal to
>:greater than
>=:greater than or equal to
>>> 1 == 1
True
>>> 1 + 1 != 2
False
>>> 5*2 >= 11
False

Warning

Beware of float comparisons, as the way computers represent floating-point numbers internally might lead to some seemingly weird behavior.

>>> 0.1 + 0.2 == 0.3
False

This is certainly unexpected behavior. To deal with this shortcoming version 3.5 of Python introduced the isclose function in its math module.

>>> import math
>>> math.isclose(0.1 + 0.2, 0.3)  
True

If you are working with an older version there are still convenience solutions. The numpy package that is introduced later on in this tutorial also provides the means for float comparisons.

In many cases a simple boolean expression is not sufficient to correctly specify the control flow of a program. Sometimes a code block should only be executed when a condition is not met, when several conditions are met all at once or when at least one of several conditions is met. For this Python hast the keywords not, and, and or, respectively. Their behavior is outlined in the following tables.

Truth table for not
A not A
True False
False True
Truth table for and
A B A and B
True True True
True False False
False True False
False False False
Truth table for or
A B A or B
True True True
True False True
False True True
False False False

Combining boolean expressions using these keywords is an essential skill for programming.

>>> i = 3
>>> i < 4 and i >= 0
True
>>> i < 4 and i > 3
False
>>> i < 4 and not i > 3
True
>>> i >= 0 or i > 3
True

You can furthermore use brackets to specify the order of the evaluation of the subexpressions like you would in equations.

Note

In Python False is not the only thing that is “false” in Python. False, None, numeric zero of all types, and empty strings and containers are all interpreted as false.

The most important construct using boolean expressions is introduced in the following.

The if statement

A construct every programming language provides is the if statement. The basic structure is as follows:

if <expression>:
    <code block>

The result is that the code block is only executed when expression is True.

Note

Test

>>> x = 0
>>> y = 1
>>> if x > 0:
...     print('Larger than 0')
...
>>> if y > 0:
...     print('Larger than 0')
...
Larger than 0

The expression can also include a negation using Boolean operations:

>>> x = 0
>>> y = 1
>>> if not x > 0:
...     print('Not larger than 0')
...
Not larger than 0
>>> if not y > 0:
...     print('Not larger than 0')
...

If you want to cover both cases you can also use the else keyword:

>>> x = 1
>>> if x < 0:
...     print('Negative')
... else:
...     print('Positive')
...
Positive

But as you can see this does not cover all the cases. What if x is 0? For this we have to use elif:

>>> x = 0
>>> if x < 0:
...     print('Negative')
... elif x == 0:
...     print('Zero')
... else:
...     print('Positive')
...
Zero

And you can add as many elifs as you want.

The while loop

Sometimes it is necessary to perform a routine until a certain condition is met. This is achieved using a while loop.

>>> x = 0
>>> while x < 5:
...     print(x)
...     x += 1
...
0
1
2
3
4

Assume you want to exit the while loop when a certain condition is met. This is possible with the break statement.

>>> x = 0
>>> while x < 5:
...     if x == 3:
...         break
...     print(x)
...     x += 1
...
0
1
2

Attention

Although while loops are a common building stone in every programming language I advise you to avoid using them whenever possible. It happens quite easily that the criterion for exiting the loop is never reached and your program gets stuck performing the same task more often than you intended. In many cases a while loop can be substituted with a for loop.

The for loop

In a lot of cases you just want to work on all the elements of a container one at a time. This is easily achieved with for loops.

>>> x = [1, 2, 3]
>>> for i in x:
...     print(i)
...
1
2
3

Here i takes on the value of the elements of x one after the other. This allows you to work with i inside of this for loop. After all elements have been visited you automatically exit the loop. A more sophisticated example might be to store the squared values of another list in a new list.

>>> x = [1, 2, 3]
>>> x_squared = []
>>> for value in x:
...     x_squared.append(value**2)
...
>>> print(x_squared)
[1, 4, 9]

range

A shortcut to loop over integers is given as the range() function.

>>> for i in range(3):
...     print(i)
...
0
1
2
>>> for i in range(3, 6):
...     print(i)
...
3
4
5
>>> for i in range(3, 12, 3):
...     print(i)
...
3
6
9

enumerate

Sometimes you also want to track where you currently are in your iteration. For example you want to know what the current state of your program is, but printing the value you are operating on each single time is kind of too much. Then you could use enumerate() like this:

>>> results = []
>>> for i, value in enumerate(range(100,900)):
...     if i % 200 == 0:
...         print('Current step:', i, '-- Value:', value)
...     results.append(i**2 % 19)
...
Current step: 0 -- Value: 100
Current step: 200 -- Value: 300
Current step: 400 -- Value: 500
Current step: 600 -- Value: 700

As you can see we now have comma-separated variables i and value. i get the current index we are in whereas value holds the actual object of the container.

zip

Another common task is that you have to loop over several lists at the same time. Use the :func:zip function for this:

>>> fruits = ['banana', 'orange', 'cherry']
>>> colors = ['yellow', 'orange', 'red']
>>> for fruit, color in zip(fruits, colors):
...     print('The color of', fruit, 'is', color)
...
The color of banana is yellow
The color of orange is orange
The color of cherry is red

Note

zip() stops the for loop as soon as one list is empty:

>>> fruits = ['banana', 'orange', 'cherry', 'apple', 'lemon']
>>> colors = ['yellow', 'orange', 'red']
>>> for fruit, color in zip(fruits, colors):
...     print('The color of', fruit, 'is', color)
...
The color of banana is yellow
The color of orange is orange
The color of cherry is red

Errors

As Python is a dynamic language it can never be garantueed that the input of your functions is what you want it to be. Take as an example a function whose purpose is the computation of the sum of the digits in a number. What if by accident someone passes a string as argument to this function? In some cases it is hence a good idea to check the input of a function for its sanity. If the input does not hold this test you may raise and error like this:

>>> raise ValueError('The input was wrong')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: The input was wrong

Summary

  • if statements are a way to add a branch into your code.
  • while loops should be avoided whenever possible.
  • for loops are used to work on items of a container.
  • range() is used to ad-hoc generate containers holding integers.
  • enumerate() is used to keep track of the current index in a for loop.
  • zip() is used to loop over several containers at once.
  • raise is used to raise an error when something is fishy.