Flow Control in Python
Video
What is Flow Control?
What we have already discussed is very useful, and machines for performing computations are old and varied.
However, in the eyes of most philosophers of programming, the one thing that separates programming from previous automation - such as the Jaquard loom - is its ability to make decisions as to what to do next. In the programming world, that is known as flow control - control of the "flow" of executed code.
Types of Flow Control
There are countless different systems for flow control in programming, but four are by far the most common:
Conditionals
The most basic type of flow control is the humble if
statement:
x=3
if x>10:
print("x is big.")
if x<= 10:
print("x is small.")
These allow the program to make more complicated decisions.
If we have opposite conditions, we can use the else
statement:
x=3
if x>10:
print("x is big.")
else:
print("x is small.")
And chain multiple conditions together with elif
:
x=3
if x>10:
print("x is big.")
elif x>0:
print("x is small.")
else:
print("x is not positive.")
Loops
The simplest loop is a while
loop. A while
loop is given a condition, and executes the loop until the condition is false. (If the condition is false, it does nothing.)
# Setup Variables
moduland = 50
modulo = 7
# Compute Modulus
modulus = moduland
while modulus > modulo:
modulus = modulus - modulo
The most common loop, however, is for
. Most languages have for
loops that are simply while
loops with some syntactic help. Python for
loops are more versatile - they loop through containers.
example_list = [1,4,9]
cube_list = []
for value in example_list:
cube_list.append(value**3)
print(cube_list)
Often, this is enough. However, you often want to iterate a certain number of times.
For that, there is the range
command:
for i in range(5):
print(i)
Note that range(5)
provides the first 5 integers, 0-indexed; that is, 0,1,2,3,4
.
Range accepts optional parameters for starting value and integer step; for example,
for i in range(1,10,2):
print(i)
prints 1,3,5,7,9
.
Breaks & Continues
We will talk about escaping more in the future, but there are two useful flow control statements within loops:
break
escapes the current loop, and moves on after it. For example:
for i in range(100):
if i==5:
break
print(i)
This is mostly used for searching for particular values - iterating until something happens.
It is a better pattern than while
loops for high intensity computing because of your easy ability to set an upper limit for loop length. But if the calculation fails, you need a way to determine it: fortunately, for
supports an else
clause which triggers if and only if the loop exists without hitting a break statement.
for i in range(100):
if i==5:
break
else:
print("Unable to find 5.")
print(i)
break
only breaks out of the closest loop. There is no way to easily break out of a higher loop just using break
.
continue
works similarly, but instead of escaping the loop, it starts the next iteration immediately:
for i in range(10):
if i%3 != i%2:
continue
print(i)
This is great for discarding cases, and is a common task in the algorithm
Functions
Functions very much count as flow control.
The main two behaviors of functions that control flow are entering and exiting.
When you call a function, execution of the parent flow is paused. Until the function executes a return
statement - or runs out of things to do - you are within the function's flow.
This can be used to escape any number of loops: for example,
def find_5():
for i in range(100):
for j in range(20):
if i == 5:
return i
print("Couldn't find 5.")
would not print its statement; it would find its value and return.
Errors
We will talk about errors in more detail later in the course.
For flow control, it is most important to know that they are raised by functions whenever they can't do what you asked. They break out of all flow - unless they are suppressed.
If your code is asked to do something it doesn't know how to do, it is best to raise an error:
raise ValueError("An Explanation of What Went Wrong.")
There are many types of builtin errors. Libraries - and you - are allowed to define new errors, which can help with specificity.
For now, the ones we will use are:
error | example | situation |
---|---|---|
TypeError |
raise TypeError("Explanation") |
used when a function is passed an argument of a type it cannot use. |
ValueError |
raise ValueError("Explanation") |
used when a function is passed an argument of a type it cannot use. |
Python Comprehensions
Python provides an abbreviated syntax for creating containers using inline flow control.
For example, to construct a list of the first 10 positive cubes, you can do:
first_10_squares = [i**3 for i in range(1,11)]
Or an example from an exploratory file in my research,
quadratic_residues = {pow(i,2,p) for i in range(p//2)}
While it can be used for complex systems, I recommend shying away from it for anything that isn't immediately clear.
Using iterable containers, list comprehensions are often used as a simple interface for filters and maps: we can pick out the floats with integer values with:
[int(i) for i in example_numbers if i.is_integer()]
You can still use the concept of maps and filters - which we are familiar with from mathematics - using the map
and filter
functions: the following two statements are equivalent.
[float(i) for i in range(10) if i%2 == i%3]
list(map(float, filter(lambda x: x%2 == x%3, range(10))))
Which may give you some insight into why people prefer the comprehension syntax.
Generators
Generators are mostly outside the scope of this class. However, there is one reason we must bring them up; you cannot create tuples with a comprehension directly; they instead create a generator.
You can think of generators as single-use lists. This makes them considerably faster, and with a lower memory footprint, in many use cases. We have already talked about a few generators - in Python 3, range
is a generator.
These can be used as arguments without the enclosing. For example, you could construct a string containing the integers with:
' '.join(str(i**2) for i in range(20))
To convert a generator to a reusable list, it is a simple typecast:
example_list = list(range(10))
Or to construct a tuple,
example_tuple = tuple(i**2 for i in example_list)
worksheet
Today's worksheet will get you using loops and comprehensions, as well as some design.