Code Structures I: Conditionals, Loops, and Comprehensions¶
1 Checking cases: if
, elif
, and else
¶
1.1 The simple case with if
and else
¶
We start with one of the simplest code structures: if
and else
. These statements are used to check the truth-value of a particular condition and, depending on whether it is evaluated to be True
or False
, run a code block.
recession = False
if recession:
print('Booh!')
else:
print('Yay!')
Yay!
What did the code do here? In the first line, we assigned the boolean False
to the variable recession
. In the second line, we check the truth value of the expression recession
. Since it is equal to False
, the indented code block starting in the third block is not executed. Instead, the indented code behind the else:
expression is executed.
Note that the expression whose truth value we check is not written in parentheses as in other languages but concluded with a colon. Moreover, the code to be executed after the if
and else
statements is also not set in brackets but indented. This gives the code a very clean and tidy look.
Of course, you can also nest if
-else
structures within each other but I won’t show it here as it is straightforward.
1.2 Checking several cases with elif
¶
So, what if you want to check more than one case? Use elif
!
color = 'violet'
if color == 'red':
print('It is a tomatoe!')
elif color == 'yellow':
print('It is a yellow pepper!')
elif color == 'violet':
print('It is an onion!')
else:
print('No idea what this is.')
It is an onion!
We assigned the string 'violet'
to the variable 'color'
. The second line checked whether the variable color
is equal to the string 'red'
. This was evaluated to be False
so Python did not execute the indented code and jumped to the next condition. It then checked the second expression. Color was also not equal to yellow it again skipped the indented code. Finally, the third expression turned out to be True
, so Python printed the string 'It is an onion!'
.
1.3 Comparison operators¶
In the previous example, we used the equality operator ==
. Let’s briefly run through the different comparison operators that Python has to offer:
==
: equality!=
: inequality<
: less than<=
: less than or equalin
: membership.
Finally, to combine expressions you want to check, use the boolean operators and
and or
. If you want to negate a statement, use not
. So, let’s play around a little bit.
x = 7
x < 7
False
x <= 7
True
number_list = [5, 6, 7]
x in number_list
True
x not in number_list
False
x < 5 or x >= 7
True
x < 5 and x >= 7
False
5 < x < 10
True
It might make sense to use parentheses in order to organize the precedence of expressions.
(x < 5) and (x >= 7)
False
2 Repeat with while
loops¶
Sometimes, instead of checking cases, you want to repeat a certain action until a condition has been met. You can do this with a while loop.
count = 1
while count <= 5:
print(count)
count += 1
1
2
3
4
5
In the first line, we assigned the value 1
to the variable count
. Then, the actual loop started. In the second line, the value of the condition count <= 5
is checked. In the first run, this expression is equal to True
. Therefore, the indented code is executed and the variable count
is increased by one. The loop is repeatedly executed until count = 6
. Then, the expression count <= 5
is equal to False
and the loop ends.
If you want to repeat a loop until something happens, but you don’t know when it occurs, you can use the break
command.
while True:
string = input('String to capitalize (type q to quit):')
if string == 'q':
break
print(string.capitalize())
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
/tmp/ipykernel_2310/4008045787.py in <module>
1 while True:
----> 2 string = input('String to capitalize (type q to quit):')
3 if string == 'q':
4 break
5 print(string.capitalize())
/opt/hostedtoolcache/Python/3.8.11/x64/lib/python3.8/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
1001 """
1002 if not self._allow_stdin:
-> 1003 raise StdinNotImplementedError(
1004 "raw_input was called, but this frontend does not support input requests."
1005 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
This loop is repeated infinitely since the expression True
is always True
. However, Python let’s you break out of the loop with break
if a certain condition is met. In this case, this condition is that you type in the string 'q'
. We can combine our code snippet with continue
to skip the rest of the loop and directly start with the next iteration.
while True:
value = input('Odd integer, please (type q to quit):')
if value =='q':
break
number = int(value)
if number % 2 == 0:
continue
print(number, ' squared is ', number * number)
Odd integer, please (type q to quit):2
Odd integer, please (type q to quit):3
3 squared is 9
Odd integer, please (type q to quit):q
3 Iterate with for
loops¶
3.1 Looping over lists¶
The use of a for
loop is particularly helpful if you want go through an iterable object, such as a list. To see the situation, look at the following while
loop which goes through a list and prints out each element.
economists = ['Hayek', 'Keynes', 'Marshall', 'Krugman']
current = 0
while current < len(economists):
print(economists[current])
current += 1
Hayek
Keynes
Marshall
Krugman
While this code snippet works it is certainly not elegant, since we have to create and repeatedly increment the counter current
to loop through the list. A simpler way using a for
loop would be as follows.
economists = ['Hayek', 'Keynes', 'Marshall', 'Krugman']
for economist in economists:
print(economist)
Hayek
Keynes
Marshall
Krugman
This loop automatically creates the variable economist
which with each iteration of the loop takes the value of a different element from the lists economists
. The loop proceeds until it has gone through the whole list.
3.2 Looping over strings and dictionaries¶
There are also other iterable objects, such as strings or dictionaries. In the case of a string, the iteration loops through the characters of the string.
word = 'Samuelson'
for letter in word:
print(letter)
S
a
m
u
e
l
s
o
n
So what happens if we loop over a dictionary?
biography = {'name' : 'Hayek', 'affiliation' : 'University of Freiburg', 'nationality' : 'Austrian'}
for element in biography:
print(element)
name
affiliation
nationality
As you can see, a for
loop without qualification runs through the keys of the dictionary. What if we want to loop through the values?
biography = {'name' : 'Hayek', 'affiliation' : 'University of Freiburg', 'nationality' : 'Austrian'}
for element in biography.values():
print(element)
Hayek
University of Freiburg
Austrian
Finally, what if we want the loop to return both the key as well as the corresponding values? Use the items
function!
biography = {'name' : 'Hayek', 'affiliation' : 'University of Freiburg', 'nationality' : 'Austrian'}
for element in biography.items():
print(element)
('name', 'Hayek')
('affiliation', 'University of Freiburg')
('nationality', 'Austrian')
In this case, each item is assigned a tuple with two values. What if we want to have both elements separately? Remeber the cool assignment trick for tuples?
biography = {'name' : 'Hayek', 'affiliation' : 'University of Freiburg', 'nationality' : 'Austrian'}
for key, value in biography.items():
print('The key is ' + key + ' and the corresponding value is ' + value + '.')
The key is name and the corresponding value is Hayek.
The key is affiliation and the corresponding value is University of Freiburg.
The key is nationality and the corresponding value is Austrian.
3.3 Looping over several lists with zip
¶
What if we want to loop over several lists at once? This is possible with the zip
function.
economists = ['Hayek', 'Keynes', 'Marshall', 'Krugman']
icecreams = ['chocolate', 'vanilla', 'coconut', 'cookie']
for economist, icecream in zip(economists, icecreams):
print(economist + ' loves ' + icecream + ' icecream.')
Hayek loves chocolate icecream.
Keynes loves vanilla icecream.
Marshall loves coconut icecream.
Krugman loves cookie icecream.
These sweet-tooths…
3.4 Generating sequences of numbers with range
¶
Sometimes you want to iterate through a sequence of numbers. These sequences can be easily created with the range
function.
# range(start, stop, step)
# default value is 0 for start, and 1 for step
for value in range(3):
print(value)
0
1
2
As with slicing, the right side of the offset range is not included.
for value in range(2, 4, 1):
print(value)
2
3
for value in range(4, -1, -1):
print(value)
4
3
2
1
0
By the way, the range
function can also be used to create lists of sequences quickly.
list(range(3))
[0, 1, 2]
4 Comprehensions¶
4.1 List Comprehensions¶
There is another feature of the Python language which sometimes helps you in avoiding complicated structures of loops and conditional tests: comprehensions. This is already an advanced topic but once you get it, you will (might) love it! Let’s create a list with the numbers 1 to 6. We already now several ways to do this.
number_list = []
number_list.append(1)
number_list.append(2)
number_list.append(3)
number_list.append(4)
number_list.append(5)
number_list.append(6)
print(number_list)
[1, 2, 3, 4, 5, 6]
number_list = list(range(1,7))
print(number_list)
[1, 2, 3, 4, 5, 6]
number_list = []
for number in range(1, 7):
number_list.append(number)
print(number_list)
[1, 2, 3, 4, 5, 6]
Now, the easiest way to do the same thing using a comprehension is as follows.
number_list = [number for number in range(1,7)]
print(number_list)
[1, 2, 3, 4, 5, 6]
The general syntax is [expression for item in iterable]
. You might not see the advantage yet. We will get there. First, note that expression can also be something more complicated. In the following, I create a list with the squares of the numbers from 1 to 6.
number_list = [number**2 for number in range(1,7)]
print(number_list)
[1, 4, 9, 16, 25, 36]
Secondly, we can extend the basic structure to [expression for item in iterable if condition]. Let’s say we want to construct a list out of all the odd numbers between 1 and 20.
number_list = [number for number in range(1, 21) if number % 2 == 1]
print(number_list)
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
Finally, you can also have several iterables. Let’s say we want to loop through every combination of columns and rows.
The first way to do this would be with nested for
loops.
rows = range(1, 5)
cols = range(1, 3)
for row in rows:
for col in cols:
print(row, col)
1 1
1 2
2 1
2 2
3 1
3 2
4 1
4 2
A similar thing can also be done with list comprehensions, where we create a tuple for every combinations of rows and columns.
rows = range(1, 5)
cols = range(1, 3)
cells = [(row, col) for row in rows for col in cols]
print(cells)
[(1, 1), (1, 2), (2, 1), (2, 2), (3, 1), (3, 2), (4, 1), (4, 2)]
If we want to have exactly the same result, we have to unpack the tuples again.
for row, col in cells:
print(row, col)
1 1
1 2
2 1
2 2
3 1
3 2
4 1
4 2
4.2 Dictionary Comprehensions¶
Similar structures can also be used to create dictionaries. The expression is {key_expression : value_expression for item in iterable}
. Say we want to store the numbers from 1 to 10 together with their squares.
squares_dict = {number : number**2 for number in range(1,11)}
print(squares_dict)
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}
Sources¶
The structure of exposition was taken from Bill Lubanovic (2015): Introducing Python: Modern Computing in Simple Packages. O’Reilly: Sebastopol, CA.