Python - Flow Control
| Author(s) |
|
| Reviewers |
|
OverviewQuestions:
Objectives:
How can my programs do different things based on data values?
Requirements:
Write conditional statements including
if,elif, andelsebranches.Correctly evaluate expressions containing
andandor.
Time estimation: 40 minutesLevel: Introductory IntroductorySupporting Materials:Published: Apr 25, 2022Last modification: Feb 13, 2023License: Tutorial Content is licensed under Creative Commons Attribution 4.0 International License. The GTN Framework is licensed under MITpurl PURL: https://gxy.io/GTN:T00088version Revision: 3
Best viewed in a Jupyter NotebookThis tutorial is best viewed in a Jupyter notebook! You can load this notebook one of the following ways
Run on the GTN with JupyterLite (in-browser computations)
Launching the notebook in Jupyter in Galaxy
- Instructions to Launch JupyterLab
- Open a Terminal in JupyterLab with File -> New -> Terminal
- Run
wget https://training.galaxyproject.org/training-material/topics/data-science/tutorials/python-flow/data-science-python-flow.ipynb- Select the notebook that appears in the list of files on the left.
Downloading the notebook
- Right click one of these links: Jupyter Notebook (With Solutions), Jupyter Notebook (Without Solutions)
- Save Link As..
“Flow Control” is how we describe when we change the flow of code’s execution, based on some conditions. Here we’ll learn how to take different actions depending on what data out program sees, or how to run code only if some condition is true.
CommentThis tutorial is significantly based on the Carpentries Programming with Python and Plotting and Programming in Python, which are licensed CC-BY 4.0.
Adaptations have been made to make this work better in a GTN/Galaxy environment.
AgendaIn this tutorial, we will cover:
Comparators
In Python we have the following comparators to do compare two values
>: greater than<: less than==: equal to!=: does not equal>=: greater than or equal to<=: less than or equal to
They’re all “binary” comparators, we can only compare two values at a time.
print(37 < 38)
print(38 < 38)
print(39 < 38)
These print out True or False, these are the two possible values of the boolean datatype in Python.
We can use <= to check if it’s less than or equal to:
print(19 <= 20)
print(20 <= 20)
print(21 <= 20)
And we can use == for comparing numbers in Python
print(11 == 11)
print(11 != 11)
print(22 != 33)
And now that we can compare numbers, we can start doing useful things with them!
Conditionals
We can ask Python to take different actions, depending on a condition, with an if statement:
num = 37
if num > 100:
print('greater')
else:
print('not greater')
print('done')
The second line of this code uses the keyword if to tell Python that we want to make a choice.
If the test that follows the if statement is true,
the body of the if
(i.e., the set of lines indented underneath it) is executed, and “greater” is printed.
If the test is false,
the body of the else is executed instead, and “not greater” is printed.
Only one or the other is ever executed before continuing on with program execution to print “done”:
Conditional statements don’t have to include an else. If there isn’t one,
Python simply does nothing if the test is false:
num = 53
print('before conditional...')
if num > 100:
print(f'{num} is greater than 100')
print('...after conditional')
Question: If behaviourTry changing the
numvalue and see what happens for different values.What happens if
numis a:
- 202
- 3.145
- “test”
- 100.000001
- Condition is activated!
- Nothing, but not because it is a float! Because it’s less than 100
- Traceback, a
TypeError, you cannot compare strings with integers- Condition is activated!
Multiple Branches
But what if you want more branches? What if you need to handle more cases? elif to the rescue!
We can chain several tests together using elif, which is short for “else if”.
if todays_temperature > 30:
print("Wear shorts! Remember your sunscreen")
elif todays_temperature > 20:
print("It's nice weather finally! Gasp!")
elif todays_temperature < 10:
print("Time to bundle up!")
else:
print("Dress normally")
if/elif/else cases follow these rules:
- must start with an
if- can have 0 or more
elifconditions- can have 0 or 1
elsecondition (if no else condition is supplied, it’s equivalent toelse: <nothing>)
Each of these three sections is a branch, the code pauses, and chooses to go down one of the branches based on the conditions.
The following Python code uses elif to print the sign of a number.
num = -3
if num > 0:
print(f'{num} is positive')
elif num == 0:
print(f'{num} is zero')
else:
print(f'{num} is negative')
NB: To test for equality we use a double equals sign ==
rather than a single equals sign = which is used to assign values.
Combining Tests
We can also combine tests using and and or.
and is only true if both parts are true:
a = 1
b = -1
if (a > 0) and (b <= 0):
print('both parts are true')
else:
print('at least one part is false')
Question: Predict what happensPredict the outcomes of the following values of
aandbabove. Predicting what you think the code will do is a useful skill to practice
- a = 0; b = -1
- a = 0; b = 10
- a = 4; b = -22
- a = 99; b = 99
- at least one part is false
- at least one part is false
- both parts are true
- at least one part is false
while or is true if at least one part is true:
a = 1
b = -1
if (a < 0) or (b > 0):
print('at least one test is true')
TrueandFalseare special words in Python calledbooleans, which represent truth values. A statement such as1 < 0returns the valueFalse, while-1 < 0returns the valueTrue.
True and False booleans are not the only values in Python that are true and false.
In fact, any value can be used in an if or elif. This is commonly used to
check, for instance, if a string is empty or if some data is provided:
if '':
print('empty string is true')
if 'word':
print('word is true')
You can also use it to check if a list is empty or full:
if []:
print('empty list is true')
if [1, 2, 3]:
print('non-empty list is true')
# The last statement is equivalent to:
if len([1, 2, 3]) > 0:
print('non-empty list is true')
Or you can check if a number is zero, or non-zero:
if 0:
print('zero is true')
if 1:
print('one is true')
Inverting Conditions
Sometimes it is useful to check whether some condition is not true.
The Boolean operator not can do this explicitly.
After reading and running the code below,
write some if statements that use not to test the rule
that you formulated in the previous question.
not is a unary (not binary) operator: it only takes a single value
if not '':
print('empty string is not true')
if not 'word':
print('word is not true')
if not not True:
print('not not True is true')
Ranges
Python makes it super easy to check if a number is within a range.
quality_score = 32 # Try out different values!
if quality_score > 40:
print("Your data is a bit sus")
elif 20 < quality_score <= 40:
print("Hey that looks ok")
elif 4 < quality_score <= 20:
print("Oh you did nanopore sequencing")
else:
print("It shouldn't be *that* bad. Try again.")
There are two important points here:
20 < x < 40is equivalent to20 < x and x < 40, checking both sides of the condition, to make sure it’s greater than one value and smaller than another- Note that we checked in the second case
20 < xand then in the third we had to checkx <= 20. If we had not had a<=on one side, what would have happened to 20? It would have gone straight to else!
Exercises
Question
ifs,elifs andelses get evaluated in blocks. Look at the following code and list the lines that are part of a single block.1. if x: 2. # .. 3. if y: 4. # .. 5. elif z: 6. # .. 7. if q: 8. # .. 9. else: 10. # .. 11. elif t: 12. # .. 13. else e: 14. # ..“Blocks” of if/elif/elses
- must start with an
if- can have 0 or more
elifconditions- can have 0 or 1
elsecondition (if no else condition is supplied, it’s equivalent toelse: <nothing>)The above blocks are parsed together, you could not insert a
- 1-2, Just an
ifby itself. There’s no elif, or else, so that’s the end of that block- 3-6,
ifandelifget evaluated, there is noelse, so that’s the end of that block- 7-10,
ifandelseis fine- 11-14, error! This is missing an
ifcase, it will fail with a syntaxerror.
# Test code here.
Question: How Many Paths?Consider this code:
if 4 > 5: print('A') elif 4 == 5: print('B') elif 4 < 5: print('C')Which of the following would be printed if you were to run this code? Why did you pick this answer?
- A
- B
- C
- B and C
C gets printed because the first two conditions,
4 > 5and4 == 5, are not true, but4 < 5is true.
# Test code here.
Question: Close EnoughWrite some conditions that print
Trueif the variableais within10of the variablebandFalseotherwise. Compare your implementation with your partner’s: do you get the same answer for all possible pairs of numbers?There is a [built-in function
abs][abs-function] that returns the absolute value of a number:print(abs(-12))12a = 5 b = 5.1 if abs(a - b) <= 10: print('True') else: print('False')print(abs(a - b) <= 10)This works because the Booleans
TrueandFalsehave string representations which can be printed.
# Test code here.
Question: PitfallsA integer number between 0 and 100 will be provided to this function. Answer these two questions:
- Will it always print something? If not, which value(s) fail?
- Can you find any numbers the programmer explicitly wanted to handle, that aren’t handled as expected?
num = 42 # Randomly chosen so the code will execute, try changing it around. if num > 90: print("great score") elif num < 32: print("Very cold") elif num >= 86: print("Almost") elif num == 86: print("It's exactly this value!") elif 32 < num < 58: print("Getting warmer") elif 57 < num <= 86: print("Everything else goes here")
- No, it won’t. 32 is the only value there that doesn’t print anything. You can either do
x < 57and later57 <= xto test the bigger and smaller values, or you can make usex < 57and56 < x, which have the same results, but only with integers. If your code accepted a float, e.g.56.5, both of those tests would be true. Sox < 57and later57 <= xis the preferred way to write that.86is the most obvious solution to this, the programmer added a check specifically to see if the value was 86, but instead it’s caught by the previous case.
num = 42 # Randomly chosen so the code will execute, try changing it around.
if num > 90:
print("great score")
elif num < 32:
print("Very cold")
elif num >= 86:
print("Almost")
elif num == 86:
print("It's exactly this value!")
elif 32 < num < 58:
print("Getting warmer")
elif 57 < num <= 86:
print("Everything else goes here")
Complicated if/elif/else cases are common in code, you need to be able to spot these sort of issues. For example there are large if/else cases in the Galaxy codebase, sometimes nested even, and being ale to predict their behaviour is really important to being able to work with the code. Missing else cases are sometimes important, sometimes a bug, sometimes just the code hasn’t been implemented yet, which is why we always write good code comments!
