Decision Making With if, else, and elif¶
Note: Using Jupyter notebbooks — or starting to explore Spyder.
For the exercises here (and in later units) you can work in a Jupyter notebook, or if you prefer, you can start working with Python code files (suffix “.py”), using the Spyder IDE.
If you work with Python files, then also put that code into a notebook (suggested name “Unit02.ipynb”) and submit both the notebook and any Python files.
Introduction¶
To move beyond using Python to execute a simple sequence of commands, two new algorithmic features are needed: decision making and repetition (with variation).
In this unit we look at decision making, using conditional statements; if
statements.
We first see the simplest case of either doing something or not, depending on some condition; here, avoiding division by zero. The code we will use first is:
if b == 0:
print('Do you really want to try dividing by zero?!')
print(f'{a}/{b} = {a/b}')
Now to test it with various values of a
and b
.
Initially I will duplicate the code for each test case, but later we will see how to avoid repeating yourself, by either editing the code in the notebook or using commands for repetition.
It is all fine with
a = 4
b = 3
if b == 0:
print('Do you really want to try dividing by zero?!')
print(f'{a}/{b} = {a/b}')
4/3 = 1.3333333333333333
but not with
a = 4
b = 0
if b == 0:
print('Do you really want to try dividing by zero?!')
print(f'a/b = {a/b}')
Do you really want to try dividing by zero?!
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-4-87a112b07258> in <module>
1 if b == 0:
2 print('Do you really want to try dividing by zero?!')
----> 3 print(f'a/b = {a/b}')
ZeroDivisionError: division by zero
There are several points to note here:
Testing for equality is done with a double equal sign, to distinguish from assigning a value to the variable at the left, which is what
b = 0
does.Statement like the above
if ...
that control the execution of a subsequent list or block of statements ends with a colon, and statements in the following block are indented by four spaces. Avoid using tabs for indentation! (The JupyterLab and Spyder editors do this indentation automatically when you press “return” after a line of code that ends with a colon.)The end of the collection of controlled statements in indicated simply by the end of that indentation; unlike some other programming languages, there is no line
end
, orend if
or such. So the secondprint
statement is not in the “if block”, and is executed regardless of what happens in theif
statement.Thus we see that in Python, indentation has meaning; it is not just for readability. (Aside: this and the previous point mimic typical English language style for lists, as indeed in the current cell!)
This code illustrates a classic bit of bad programming: detecting a problem but then not doing anything about it!
On that last point, the next form of conditional statement specifies actions for both the True
and False
cases, using an else
clause for the latter:
a = 4
b = 0
if b == 0:
print('You cannot divide by zero! Try changing the value of b and rerun this cell.')
else:
print(f'{a}/{b} = {a/b}')
We can break this into pieces, to see first what b == 0
does:
answer = (b == 0)
print(f"The answer is {answer}")
Note that logical statements like b == 0
have value either True
or False
— and remember that these are case sensitive; “true” and “false” have no special meaning.
if answer:
print('You cannot divide by zero! Try changing the value of b and rerunning this cell.')
else:
print(f'{a}/{b} = {a/b}')
Next, exercise the other “else” option.
Aside: it is good code development practice to use a collection of tests which ensure that every piece of code is executed.
a = 4
b = 3
answer = (b == 0)
print(f"The answer is {answer}")
if answer:
print('You cannot divide by zero! Try changing the value of b and rerun this cell.')
else:
print(f'{a}/{b} = {a/b}')
Aside: avoiding code duplication, with the for
statement
We will learn about commands for repetition in a later unit, but just as a preview, here is an example of how to do a succession of similar things without duplicating lines of code.
Also note the two levels of indentation, each with four spaces.
a = 4
for b in [3, 0]:
print(f'With a = {a} and b = {b},')
if b == 0:
print('b is 0; you cannot divide by zero!')
else:
print(f'{a}/{b} = {a/b}')
Here is another way to do the same thing, this time putting the more “normal” case first, which tends to improve readability:
a = 4
b = 3
if b != 0: # Note: This is the notation for "is not equal to".
print(f'{a}/{b} = {a/b}')
else:
print('b is 0; you cannot divide by zero!')
Handling multiple possibilities¶
More than two possibilities can be handled, using an elif
clause (short for “else, if”). Let’s see this, while also introducing inequality comparisons:
x = 4
if x > 0:
print('x is positive')
elif x < 0:
print('x is negative')
else: # By process of elimination ...
print('x is zero')
Exercise A¶
Test the above by changing to various other values of x
and rerunning.
As mentioned above, ensure that you exercise all three possibilities.
While experimenting in a notebook (or Python code file), one way to do this is to edit in new values for x
and then re-run, but for final presentation and submission of your work, do this by one of the methods seen above:
make multiple copies of the code, one for each chosen value of
x
.be more adventurous by working out how to use a
for
statement to run a list of test cases. This is looking ahead to Section 5: Iteration with for.
There can be as many elif
clauses as you want.¶
In the following, remember from the introduction that a % b
is the remainder after integer division of a by b:
n = 36
if n % 10 == 0:
print(f'{n} is a multiple of ten')
elif n % 5 == 0:
print(f'{n} is an odd multiple of five')
elif n % 2 == 0:
print(f'{n} is even, but not a multiple of five.')
else:
print(f'{n} has no factor of either two or five.')
Exercise B¶
Again, test all four possibilities by using a suitable collection of values for n
.
Plan before you code!¶
Start with written preparation and planning of your procedure, and check that with me before creating any Python code.
You can do this on paper or a text file, but as a goal for how best to do things, you could also try to present this planing in a Jupyter notebook; then you could append the Python work to that notebook later.
As part of this planning, select a collection of test cases that explore all the possibilities:
keep in mind the goal that each line of code is executed in a least one test case (bearing in mind that if
statements can skip some lines of code, depending on whether various statements are true or false).
Exercise C. Planning for robust handling of all possible “quadratics” \(ax^2 + bx + c = 0\)¶
In the next exercise, we will create Python code that correctly handles the task of finding all the real roots of a quadratic equation \(ax^2 + bx + c = 0\) for the input of any real numbers \(a\), \(b\) and \(c\).
Before writing any code, we need a written plan, distinguishing all qualitatively different cases for the input, and deciding how to handle each of them. (This planning and decision making will be an important requirement in many later exercises.)
Produce quadratic solving code that is robust; handling all possible triples of real numbers a, b and c for the coefficients in equation \(ax^2 + bx + c = 0\).
Not all choices of those coefficients will give two distinct real roots, so work out all the possibilities, and try to handle them all.