Control flow and functions
On this page we will take a look at control flow and functions.
- Control flow - Ways to alter the top to bottom execution of code.
- Function - Named group of lines of code that can be executed by invoking its name.
It's not as scary as it sounds.
Control flow
The Python Tutorial - 4. More Control Flow Tools
I linked the section on control flow from Python's official tutorial above. I find the tutorial a bit hard to follow in general, but this section seems alright. I won't go through everything from the tutorial.
We will take a look at:
if,elseandelifwhileloopsforloopsbreakcontinue- and functions a bit later on
Everything on this page is essential to programming in many different programming languages. With these building blocks you are able to start making things.
TODO: I should write about try / except later.
if, else and elif
There are cases in life where depending on some factor you either want to do one thing or do some other thing.
For example, if you are studying for a test you may want to focus on studying the parts you don't know well.
If you are worse at statistics than heat flux then you should study statistics, otherwise (else) you should study
heat flux. Software also need to do these kinds of decisions. if, else and elif
allows your code to make decisions. In one case do this, in another case do that.
Let's look at a case where you either want to do something or do nothing.
ENERGY_THRESHOLD = 5
sleep_hours = 8
hours_since_last_meal = 4
if sleep_hours - hours_since_last_meal > ENERGY_THRESHOLD:
print("I am going to study!")
This program tells me if I should study (or not). I run this program every day. Notice how I put
ENERGY_THRESHOLD in capital letters. This tells other developers that the variable is a constant and
should not be changed after it has been assigned a value.
Let's look at the syntax for if. There's an if-statement (the characters "if"), followed by an expression that
evaluates to True or False, followed by a colon. The line after the colon is indented, indicating we're in a new block of
code. The indented code is only run if the expression in the if-statement evaluates to True.
Let's put the "study statistics or heat flux" example into code.
STATISTICS_PROFICIENCY = 4
HEAT_FLUX_PROFICIENCY = 2
if STATISTICS_PROFICIENCY < HEAT_FLUX_PROFICIENCY:
print("I am going to study statistics!")
else:
print("I am going to study heat flux!")
We have an if-statement with a condition. As before, if the if-statement is True, the indented
code on the row below is run. However, if the if-statement is False, the indented code under else: is run instead.
We have seen cases with one if and one else. What if we want to handle more cases?
current_energy_level = 5
if current_energy_level >= 7:
print("I should go to the big store far away for groceries.")
elif current_energy_level >= 5:
print("I should go to the medium size store that's fairly close.")
elif current_energy_level >= 3:
print("I should go to the small store that's around the corner.")
else:
print("I should rest.")
"elif" is short for "else if". else if is common in other programming languages, but it's called elif in Python.
Here we use elif followed by expressions that evaluates to True or False to decide which store to visit. You can have zero
or more elifs. You can also have elif without else. You cannot have elif or else
without if.
Now here's an interesting question: What will the output be? current_energy_level is 5, so looking at the
code it does not seem unreasonable that the code for both elifs and the else will run. In actuality the
output will be "... medium size store ...". The code runs from top to bottom. When a condition is True, the indented code
under the if statement runs and the other conditions are not even evaluated. The fact that the other conditions are not
evaluated can have implications for performance, but that's a different topic.
Let's look at one final thing about if-statements. Namely nesting.
current_energy_level = 5
if current_energy_level < 3:
print("I should rest.")
else:
if current_energy_level >= 7:
print("I should go to the big store far away for groceries.")
elif current_energy_level >= 5:
print("I should go to the medium size store that's fairly close.")
else:
print("I should go to the small store that's around the corner.")
The code above is almost equivalent to the previous example. It produces the same result but does it
in a different way. Under the else case there's another if/elif/else-statement. You can
nest if-statements how much you want. In this case ("case" as in "situation") I think the nested statement
doesn't help with readability, but in other cases it might.
Loops
Often you want to run some specific lines of code many times, maybe once for every item in a list. You can do this with loops. Python has two different kinds of loops.
while- Runs while the provided condition is True.for- Iterates through all elements in a sequence (for example list or range).
Both of these loops supports the keywords break and continue, which
we will look at soon.
Let's look at a while loop.
x = 5
while x > 0:
print(x)
x -= 1 # Fancy shorthand for x = x - 1
The while loop takes a condition, x > 0 in this case, and runs the loop body (indented code)
until the condition is False. After each iteration it will re-evaluate the condition. This code
will output:
5
4
3
2
1
Let's unroll the loop (write equivalent code but without the loop)!
x = 5
print(x)
x -= 1
print(x)
x -= 1
print(x)
x -= 1
print(x)
x -= 1
print(x)
x -= 1
When you only loop five times and the code inside the loop is simple you don't really need a loop, but
I think even in this case the while loop version looks nicer. However, if you want to repeat
the same action 5000 times, or an unknown number of times, you definitely want a loop.
What do you think this does?
while True:
print("AAAAAAAAAAAAAHHHHH!")
Correct! It will loop and print "AAAAAAAAAAAAAHHHHH!" forever!
for loops are a bit more interesting. In Python, for loops expects a sequence they can
iterate over. We will look at iterating over a list and over a range. Let's start with a list!
cool_greetings = ["What's up?", "Howdy!", "*nods head*"]
for greeting in cool_greetings:
print(greeting)
Predictably the output will be:
What's up?
Howdy!
*nods head*
The syntax is for, followed by a name that will be assigned to the current
element in the loop body, then in, followed by the target sequence.
The range() type is often used with for loops.
for i in range(5):
print(i)
The output of this loop is:
0
1
2
3
4
A range generates a list of numbers that you can loop through. One interesting detail
is that range(4) does not generate the complete [0, 1, 2, 3, 4] list at once,
instead it only generates the next value as needed. In fact, the function only keeps track of three
values at any given time.
Sometimes you want to access list elements via an index (position).
cool_greetings = ["What's up?", "Howdy!", "*nods head*"]
for i in range(len(cool_greetings)):
print(cool_greetings[i])
The length of cool_greetings is 5, so range(len(cool_greetings)) becomes
range(3). The first item in a list is located at index 0, the variable i
is assigned a value produced by range(3) each iteration. In the first iteration i
is 0, so print(cool_greetings[i]) will print the greeting located at index 0. And so on.
Break - exit a loop early
Exiting a loop early can be useful. If you're after something specific in a list and want to leave
when you've achieved whatever task you wanted to you can use the break keyword to exit
the loop. This is also good for performance. No need to loop more than necessary.
hide_and_seek = ["Old man", "Waldo", "Lambert", "John"]
for hider in hide_and_seek:
if hider == "Waldo":
print("Waldo is hiding in this list!")
break
In this case we've been given a list of strings and our employer wants to know if the string
"Waldo" is hiding in somewhere in the list. We loop through the elements, check if the current
element, hider, is equal to "Waldo" and exit the loop if it is.
Continue - skip current loop iteration
In some cases you want to skip the current loop iteration and jump to the next.
temperatures_c = [31.2, 30.1, None, 12.3]
for t in temperatures_c:
if t == None:
print("Found invalid data. Skipping current iteration.")
continue
print(f"{t} C = {t * 9/5 + 32} F") # Fancy f-string format
In the code above we loop through a list of temperatures that's presumably in celsius.
If we run across invalid data, represented by None in this case, we skip
the current iteration. Otherwise we print the value converted to fahrenheit.
This is the output:
31.2 C = 88.16 F
30.1 C = 86.18 F
Found invalid data. Skipping current iteration.
12.3 C = 54.14 F
Both while and for loops support break and continue.
Functions
The Python Tutorial - 4. More Control Flow Tools - Defining Functions
A function is a named group of lines of code that performs some action and optionally returns a value. Functions are a helpful way to organize code and expose functionality.
From the tutorial: "The keyword def introduces a function definition. It must be followed by the function name and the parenthesized list of formal parameters. The statements that form the body of the function start at the next line, and must be indented." To call a function you write the name, followed by parenthesis and the required parameters (if any).
It's easier to understand in code:
def celsius_to_fahrenheit(temp_in_c):
return temp_in_c * 9/5 + 32
result = celsius_to_fahrenheit(20)
print(result) # 68.0
The function celsius_to_fahrenheit() takes a parameter temp_in_c, calculates
the degrees in fahrenheit and returns the result using the return statement. When the code
reaches a return statement, the function finishes. If you have put code after return,
that code will not run.
As mentioned in the tutorial, you can start the first line of the function body (the indented code), with a string literal describing what the function does. The string in that context is called a "docstring", and it should, by convention, be written in with triple quotes. The PEP (Python Enhancement Proposal) for docstrings is found here: PEP 257 - Docstring Conventions. PEPs are sort of agreed upon specifications, or conventions, for Python.
def celsius_to_fahrenheit(temp_in_c):
"""Takes temperature in celsius as a number and returns it in fahrenheit."""
return temp_in_c * 9/5 + 32
Above is an example of what a docstring can look like. Below I will link the documentation for the request class in a Python web framework called Falcon. I will also link the source code for the class. I'm only adding these links to illustrate that docstrings can be very detailed (which is good when you write documentation for external users).
Source code (note the detailed docstring): falcon.Request
There are more things regarding functions that can be useful to know:
- Functions without
returnimplicitly returns the valueNone. - Functions can
returnother functions. - You can have default values for parameters.
- You can write functions that doesn't take parameters, but you still need
(). -
The actual values you pass to a function when you invoke it are called "arguments". In the first
celcius_to_fahrenheit()example,20is the argument andtemp_in_cis the parameter. - Skipping ahead: There's a concept similar to functions called methods. They are like functions except tied to a class.
You can read more about functions in the official Python tutorial I linked earlier.
Next: Exercises