Often we want to give some output only when the correct conditions have been met. Then we use the if keyword, followed by elif for any other conditions, and then else for the default behaviour if no conditions have been met. The expression immediately following 'if' or 'elif' nust return a Boolean (True or False), and can be any expression which does return a Boolean. This includes comparisons such as < or ==, use of keywords such as in or is, or even function calls. You will also see in these examples how python uses indentation to organise code blocks.
a = input("Enter a number: ")
b = input("Enter another number: ")
# notice the lines containing the keywords if, elif, else all end in :
if (a < b):
# this will only happen when the condition (a < b) evaluates to True
print('{} is less than {}'.format(a,b))
elif (a > b):
print('{} is greater than {}'.format(a,b))
else:
print('Neither value is bigger')
It's fine to just have the 'if' part of the statement and leave out the 'elif' and/or 'else' parts.
list_of_names = ['Fred', 'George', 'Sam']
# using the 'in' keyword for lists returns a Boolean.
# any expression that returns a Boolean value can be used as part of an 'if' statement
if 'Fred' in list_of_names:
print('Yes, I know Fred!')
# there's no need to have an 'elif' part, we can go immediately to 'else'.
else:
print('Who is Fred??')
list_of_names = []
if 'Fred' in list_of_names:
print('Yes, I know Fred')
# this condition checks if the list is empty
elif len(list_of_names) == 0:
print('Who am I talking to?')
# there's no requirement to have an 'else' part -- in this case the default behaviour is just to do nothing.
There is no limit on the length or complexity of the expression following 'if'. As long as Python can evaluate the expression to return a Boolean then the code will run. However you should try to avoid very complicated conditions because they are harder for people to understand so it's easy to introduce logical errors. Overly complicated conditions could be an indication that you need to rethink how your code is structured.
list_of_numbers = [1, 2, 3, 4, 5]
if sum(list_of_numbers) > 3 and max(list_of_numbers) == 5 or min(list_of_numbers) < 1:
print('I like these numbers')
Comditional statements can be nested, so the block of code that is executed following an if statement can contain another if statement. Again, Python doesn't limit how many levels of nesting you can use but it will becomem harder to read and understand code that has too many nested conditionals.
list_of_numbers = [1, 2, 3, 4, 5]
if sum(list_of_numbers) > 3:
if max(list_of_numbers) == 5:
print('I like these numbers')
else:
print('I guess these numbers are OK')
elif min(list_of_numbers) < 1:
print('I guess these numbers are OK')
As soon as one condition evaluates to True python will not check the others. In the following code the first and second condition would both evaluate to True but only one sentence is printed.
bn_name = 'Ben Nevis'
bn_height = 1345
bn_country = 'Scotland'
sdn_name = 'Snowdon'
sdn_height = 1085
sdn_country = 'Wales'
if bn_height > sdn_height:
print('{} is taller than {}.'.format(bn_name, sdn_name))
elif bn_country == 'Scotland':
# only execute this if first condition is false AND second condition is true
print('{} is in Scotland.'.format(bn_name))
Although the expression following the if
and elif
keywords should return a Boolean, Python allows the flexibility for this expression to return other types which are then evaluated to True or False.
This can be quite counterintuitive at first and is a possible source of bugs.
In the cell below, try a few different values in the variable a
.
For example, the empty string evaluates to False, and all other strings evaluate to True -- including the string "False".
The integer 0 evaluates to False, what about positive or negative integers? Or floats?
The empty list and empty dictionary evaluate to False, all other lists and dictionaries to True.
a = 'abc'
if a:
print('{} (type {}) evaluates to True in Python.'.format(a, type(a).__name__))
else:
print('{} (type {}) evaluates to False in Python.'.format(a, type(a).__name__))
Complete the code in the next cell to return a grade and message based on the value of mark, according to the following table:
Mark | Grade | Message |
---|---|---|
0 - 40 | Fail | Try again. |
40 - 49 | Pass | Well done. |
50 - 59 | 2:2 | Good. |
60 - 69 | 2:1 | Very good. |
70 - 100 | 1st | Congratulations! |
mark = 45
grade = None
message = None
if mark < 40:
grade = 'Fail'
message = 'Try again.'
elif
print('Your mark was {}, your grade was {}. {}'.format(mark, grade, message))
Loops allow us to execute a block of code many times over. Python provides two types of loop: the first will execute a block of code while some condition is met, the second executes the code for every member of a collection of variables, or for a specified number of times.
A common reason to use a for loop is that we want to apply the same piece of code to every item in a list.
list_of_names = ['Fred', 'George', 'Sam']
for name in list_of_names:
print('Hi {}!'.format(name))
In the next cell we see how to calculate the average (mean) of a list of numbers. In fact, the python statistics module has a function for calculating the mean, but it's good to see how you could implement this function yourself. If you're not sure what the mean of a set of numbers is, have a look here https://www.mathsisfun.com/mean.html
listOfInts = [4, 7, 1, 3, 8, 9, 10, 4, 600, 3, -2, 0]
# initialise variable to keep track of the sum
total = 0
for value in listOfInts:
# add this value to the total so far
total = total + value
# now divide the sum by the number of items in the list
mean = total / len(listOfInts)
# round the answer to one decimal place
round(mean, 1)
This syntax can be used to loop over lists, tuples, and even strings. A data structure that can be used in a for loop is called iterable.
Write a loop to find the maximum from a list of numbers.
listOfInts = [4, 7, 1, 3, 8, 9, 10, 4, 600, 3, -2, 0]
# initialise a variable to keep track of the maximum
maxValue =
# loop over the list
for in :
# when should the current maximum be updated?
if :
# update the current maximum
print(maxValue)
From the given list, create a new list which contains only the even valued numbers. Hint: remember the mudulus operator (%).
listOfInts = [4, 7, 1, 3, 8, 9, 10, 4, 600, 3, -2, 0]
listOfEvens = []
# loop over the original list
for in :
# decide whether to keep this item
if :
# add item to the new list
print(listOfEvens)
Instead of using a for loop to apply the same code to every item in a list or other iterable object, we can simply specify the number of times we want the codeinside the loop to run. The range() function takes an integer and returns an iterable. The following example shows code for calculating the n-th power of x.
x = int(input('x: '))
n = int(input('n: '))
value = 1
for i in range(n):
value = value * x
print('{}**{} = {}'.format(x, n, value))
In fact, a range object has a start value, end value, and step size. When only one parameter n is given then the start value defaults to 0, the end value is n, and the step size is 1. However, you can pass more than one parameter to the function in order to explicitly set the other values. The function returns a sequence of numbers, starting from the start value, ending before the stop value, in which consecutive values differ by step. The following cell creates some range objects which are then converted to lists so you can see how the parameters affect the output. Try changing the parameters to make sure you understand what they do.
a = list(range(10))
print('stop=10: {}'.format(a))
# the same as list(range(10)) since start=0 step=1 are the defaults
b = list(range(0,10,1))
print('start=0, stop=10, step=1: {}'.format(b))
c = list(range(3,10,2))
print('start=3, stop=10, step=2: {}'.format(c))
You might want to iterate through a list and also know the index of the current list item, python provides the enumerate() function for this. The following cell gives an example to show how it works.
topBeatlesSongs = [
"She Loves You",
"I Want to Hold Your Hand",
"Can\'t Buy Me Love",
"I Feel Fine",
"Day Tripper / We Can Work It Out"
]
print("The five best selling Beatles records, in order, are:")
# enumerate returns both the index and the value of each item in the list
for index, song in enumerate(topBeatlesSongs):
# list indices start at 0 but we want to start counting at 1
num = index+1
print("{}. {}".format(num, song))
When iterating over a dictionary, by default only the dictionary keys are returned. Use the methods values(), and items() to iterate over a dictionary and have easy access to the dictionary values instead of or as well as the keys.
cityPopulations = {
'St Davids': 1841,
'St Asaph': 3355,
'City of London': 7375,
'Wells': 10536,
'Armagh': 14777,
'Ripon': 16702
}
for cityName in cityPopulations:
print(cityName)
for cityPop in cityPopulations.values():
print(cityPop)
for cityName, cityPop in cityPopulations.items():
print('The population of {} is {}'.format(cityName, cityPop))
In some situations we don't have any predetmined set of data we want to iterate over but we want to keep repeating a piece of code for as long as some condition is True. In this case, use a while loop.
x = input('Do you want to continue? y/n: ')
while x == 'y':
x = input('Do you want to continue? y/n: ')
The condition that decides whether to continue executing the code within the while block can be anything that returns a Boolean value (True or False). It is possible to make an infinite loop if this condition always evaluates to True. Occasionally that's a useful thing to do, for example if the code within the loop is able to end the execution, but it could also be a source of bugs.
The break command allows us to leave a for or while loop, continue causes the rest of the code within the loop to be skipped on this iteration and we proceed to the next iteration immediately. The bext cells give simple examples to demonstrate these ideas.
for i in range(5):
if i == 2:
continue
print(i)
for i in range(5):
if i == 2:
break
print(i)
Think carefully about where the break or continue command should sit within the code block. Compare the next cell with the previous one.
for i in range(5):
print(i)
if i == 2:
break
An advanced feature of python loops is the option to create an else block afterwards. The code within the else block will execute if the loop did not exit early (for example, due to a break statement).
n = int(input('enter an integer, n: '))
for i in range(5):
if i == n:
print('n is less than 5')
break
else:
# this code is only executed if the break statement is never reached
print('n is at least 5')
The code within a loop can itself contain loops. When reading code with nested loops think very carefully about the order in which the code will be executed. The example in the next block is intended to demonstrate this. Look carefully at the output and make sure you understand when each statement is executed.
for i in range(5):
print('outer loop index is {}'.format(i))
for j in range(5):
print('\t inner loop index is {}'.format(j))
Next we use nested loops to generate a multiplication table.
# initialize the variable
tableData = []
for i in range(1,11):
# row label
line = [str(i)]
for j in range(1,11):
line.append(str(i*j))
tableData.append(line)
# this creates nice spacing in the table
formatString = ''.join(['{:^6}']*11)
# print the header line
header = [' ']
for i in range(1,11):
header.append(str(i))
print(formatString.format(*header))
# print each line of the table
for i in range(10):
print(formatString.format(*tableData[i]))
Python includes methods for sorting a list of numbers, but using nested loops we can write our own. The next cell contains a python implementation of the Insertion Sort algorithm (https://en.wikipedia.org/wiki/Insertion_sort).
myList = [3, 6, 1, 8, 2, 0, -1]
for index, currentValue in enumerate(myList):
currentPosition = index
# As long as we haven't reached the beginning (currentPosition > 0)
# find out whether the next element left is bigger than this one.
# if yes move the larger element one space to the right.
while currentPosition > 0 and myList[currentPosition - 1] > currentValue:
myList[currentPosition] = myList[currentPosition -1]
currentPosition -= 1
# Now we've reached the correct position for this element -
# either the beginning of the list, or the next value left is smaller
# so we insert the element at currentPosition
myList[currentPosition] = currentValue
print(myList)
A different algorithm for sorting a list of numbers is called Selection Sort. Read the following description, then try to implement it in Python. You might also find it helpful to look at the introduction and example in this Wikipedia article https://en.wikipedia.org/wiki/Selection_sort.
Selection Sort In an unsorted list find the minimum element. Switch this value with the value at the first position. Now the first value of the list is the minimum value. Repeat the same procedure on the sub-list starting from the second element, then the minimum value of those remaining will be placed into the second position. Repeat the same procedure again for the sub-list starting from the third element, and so on until the whole list is sorted.
Note: this exercise is meant to be challenging! Try to understand the idea of the algorithm first before thinking about how to implement it in Python. If you get stuck then it's fine to search online for hints but make sure in the end that you can write your own implementation. For example, here's a question on Stack Overflow about implementing selection sort in Python https://stackoverflow.com/questions/15235264/selection-sort-python.
myList = [3, 6, 1, 8, 2, 0, -1]
# write a sorting procedure here
print(myList)
mark = 45
grade = None
message = None
if mark < 40:
grade = 'Fail'
message = 'Try again.'
elif 40 <= mark < 50:
grade = 'Pass'
message = 'Well done.'
elif 50 <= mark < 60:
grade = '2:2'
message = 'Good.'
elif 60 <= mark < 70:
grade = '2:1'
message = 'Very good.'
elif mark >= 70:
grade = '1st'
message = 'Congratulations!'
print('Your mark was {}, your grade was {}. {}'.format(mark, grade, message))
When setting an initial value for maxValue we need something that works for any list of numbers. If the list of numbers will definitely contain positive numbers then it's simplest to set 0 as the initial value. maxValue is updated whenever the value currently being considered from the list is bigger.
listOfInts = [4, 7, 1, 3, 8, 9, 10, 4, 600, 3, -2, 0]
# initialise a variable to keep track of the maximum
maxValue = 0
# loop over the list
for value in listOfInts:
# update the current maximum if this item from the list is bigger
if value > maxValue:
maxValue = value
print(maxValue)
What if the given list only contains negaitve numbers? Then initialising maxValue to 0 doesn't work. If the list is guaranteed to contain at least one element then maxValue could initially be set to the first element (listOfInts[0]), but what if listOfInts is empty? Here the maxValue is initialised to None, and the code within the loop ensures that this is updated if listOfInts contains any value at all. This is a better solution.
listOfInts = [4, 7, 1, 3, 8, 9, 10, 4, 600, 3, -2, 0]
# initialise a variable to keep track of the maximum
maxValue = None
# loop over the list
for value in listOfInts:
# update the current maximum if this item from the list is bigger
# also update if the current maximum is still the default value
if maxValue is None or value > maxValue:
maxValue = value
print(maxValue)
listOfInts = [4, 7, 1, 3, 8, 9, 10, 4, 600, 3, -2, 0]
# initialise new empty list
listOfEvens = []
# loop over the original list
for val in listOfInts:
# decide whether to keep this item
if val % 2 == 0:
# add item to the new list
listOfEvens.append(val)
print(listOfEvens)
Here are two ways of implementing selection sort in Python.
myList = [3, 6, 1, 8, 2, 0, -1]
# selection sort conceptually divides a list into a sorted part and unsorted part.
# each iteration increases the size of the sorted part by one.
# initially the unsorted part starts at index 0, at each iteration the start index increases by one.
# startIndex is the index of the first element of the unsorted part of the list
for startIndex, startVal in enumerate(myList):
# loop through the unsorted part of the list
# want to find the minimum value and its position
# initialise variables
minVal = None
minIndex = None
for index, val in enumerate(myList[startIndex:]):
# find the minimum
if minVal is None or val < minVal:
minVal = val
minIndex = index
# the minimum value is switched with the first value in the unsorted part
temp = myList[startIndex]
myList[startIndex] = minVal
myList[startIndex+minIndex] = temp
print(myList)
myList = [3, 6, 1, 8, 2, 0, -1]
# startIndex is the first index of the unsorted part of the list.
for startIndex in range(len(myList)):
# variable j will be used to loop through the unsorted part of the list, starting from startIndex
j = startIndex
# initialise variables for finding the position of the minimum value (in the unsorted part)
minVal = None
minIndex = None
# loop through the unsorted part of the list
while j < len(myList):
# is this item the minimum so far?
val = myList[j]
if minVal is None or val < minVal:
minVal = val
minIndex = j
# increment j to check the next item in the list
j += 1
# the minimum value is switched with the first value in the unsorted part of the list
temp = myList[startIndex]
myList[startIndex] = minVal
myList[minIndex] = temp
print(myList)