Decisions#
In the last lecture, we saw that computer programs are recipes that tell the computer what to do. Programs must be precise and correct. So far, the programs we have written have done the same things every time we run them. Here, we will see how to write code that executes only when certain conditions are true. Decisions control the flow of the program.
From individual decisions, we can build decision trees, which are an important part of expert systems. Expert systems are AI systems that have existed for a long time, and are a kind of knowledge-based systems.
The if
statement#
Say we write a program that needs to decide whether someone is a minor or adult.
We can do this with an if
test based on the age:
age = int(input("What is the defendant's age?"))
if age < 18:
print('Defendant is a minor')
Defendant is a minor
We can also include an alternate path, else
:
if age < 18:
print('Defendant is a minor')
else:
print('Defendant is an adult')
print('done')
Defendant is a minor
done
This code can be illustrated with a flowchart:
Indentation#
The code “inside” the if
statement is called a block.
Each line in a block must be indented the same amount, the convention is four spaces.
The else
statement starts another block.
if age < 18:
print('Defendant is a minor')
print('Parental consent is required')
# call a function to handle parental consent
else:
print('Defendant is an adult')
# call a function to handle consent
print('done')
Relational Operators#
if
statements start with a condition that is often some kind of comparison.
These comparisons use relational operators.
Python has six relational operators:
Relational operator |
Meaning |
---|---|
> |
Greater than |
>= |
Greater than or equal |
< |
Less than |
<= |
Less than or equal |
== |
Equal |
!= |
Not equal |
Note that the relational operator for equality is ==
, a double equal sign.
This is because a single =
is used for assignment.
We must take care to choose the correct operator to avoid off by one errors. What’s wrong here?
if age > 18:
print('Defendant is an adult')
Comparing strings#
We can also compare strings. Strings are sequences of characters. To be equal, strings must have:
The same length
The same characters, position by position
We can order strings alphabetically (lexicographically) by using relational operators. “Larger” strings come later in the alphabet:
print('Eve' < 'Jada')
True
Nested if statements#
An if
statement can contain other, nested if statements.
Nested if
statements are also called decision trees.
Their flowcharts have a tree structure.
if age < 18:
print('Defendant is a minor')
if age < 15:
print('Below age of criminal responsibility')
else:
print('Defendant is an adult')
Multiple Alternatives#
Many nested if
statements can be simplified to elif
statements, short for “else if”.
if age < 13:
print('child')
elif age < 20:
print('teenager')
elif age > 70:
print('senior citizen')
else:
print('adult')
Warning
Make sure the order of the if
tests is correct. If we had tested for teenagers before children, children would have been classified as teenagers.
Boolean Values#
The result of a condition is called a Boolean value.
Boolean values are either True
or False
.
We can assign Boolean values to variables to be used later.
For example, we might want to go through some steps to get consent for processing of personal data. We start out with no consent:
consent_given = False
# do steps to get consent
Boolean Operators#
We can combine multiple conditions into larger Boolean expressions using Boolean Operators.
valid_consent = age >= 18 and consent_given
Note
The Boolean variable consent_given
already has a truth value,
so we don’t need to use a relational operator.
Never use relational operators with True
or False
.
Don’t write if consent_given == True:
, but simply if consent_given:
There are three boolean operators: and
, or
, and not
. As we saw above, and expression with and
is True
if both sides are True
.
An expression with or
is True
if either side is True
:
parental_consent = False
valid_consent = parental_consent or age >= 18
Or we could combine all three conditions:
valid_consent = parental_consent or (age >= 18 and consent_given)
print(valid_consent)
False
The Boolean operator not
inverts the value of the expression that follows it.
Try to use variable names that results in code that reads naturally:
if not parental_consent:
print('No parental consent given')
No parental consent given
De Morgan’s Laws#
Some Boolean expressions can be simplified:
not (A or B)
is the same asnot A and not B
not (A and B)
is the same asnot A or not B
The last two expressions might be easier to read.
Notice that when we remove the parenthesis, we “flip” the operator from and to or, or the other way around. We distribute the not
operators.
These two rules are known as De Morgan’s Laws after the mathematician Augustus De Morgan.
married = True
divorced = False
if not (married and divorced):
print('do something')
if not married or not divorced:
print('equivalent with the above')
do something
equivalent with the above
Analyzing Strings#
We saw above that the standard relational operators can be used with strings.
But Python also has the in
(and not in
) operators for checking if a string contains another substring.
Note
You can copy text from code cells by clicking the Copy button in the top right corner of the cells. The Copy button appears when you place the mouse pointer inside a cell or touch it on a touchscreen.
text = '''Agreement
1. Introduction: The lender is Bank Cred AS (990 099 909).
The borrower is the person or persons (borrower and co-applicant) who apply
for and are granted a loan with this Agreement.
Payment: The credit is paid to the account number the Borrower states.
2. Repayment: The Borrower repays the loan amount at fixed term amounts, including
interest and term fees (i.e. annuity loans) as specified in the Loan Agreement.
3. Late Payment Interest: In the event of late payment, late payment interest accrues
at the interest rate determined in accordance with the Act relating to Interest on
Overdue Payments.
Signature Place/date: Oslo, 08.08.2021
For Bank Cred AS Bank adviser Maria Wilson
Name: Christopher Thomson Borrower'''
if 'signature' in text:
print('found')
else:
print('not found')
not found
Why isn’t the string signature
found in the text?
We should normalize the text to lowercase to find all possible variants.
print('signature' in text.lower())
True
Python has several methods for analyzing strings. Here are a few examples, there are many more.
print(text.startswith('Agreement'))
print(text.count('loan'))
position = text.find('Signature')
print(position)
print(text[position:])
print('text is numeric:', text.isnumeric())
print('text isalpha:', text.isalpha())
True
3
620
Signature Place/date: Oslo, 08.08.2021
For Bank Cred AS Bank adviser Maria Wilson
Name: Christopher Thomson Borrower
text is numeric: False
text isalpha: False
Input Validation#
When a program accepts input from the user, we need to check that the input is valid, that is within the range of expected answers.
This is especially important with web applications.
if
tests are a simple way of validating the input.
marital_status = input('Please input marital status, "single" or "married": ')
# normalize response by lowercaseing it
marital_status = marital_status.lower()
if marital_status == 'single':
print('calling function to handle single people')
elif marital_status == 'married':
print('calling function to handle married people')
else:
print('error: invalid marital status')
Constants#
Until now, we have used numbers like the age of majority directly in our code, hard coding the number 18 in our if
tests.
This is bad practice.
The age of majority has changed before and it might change again.
If this happens, we will need to track down every occurrence of it in our code, and change them to the new age.
To avoid this, we can make a constant once, and use that.
By convention, constant are in all capital letters.
AGE_OF_MAJORITY = 18
if age < AGE_OF_MAJORITY:
print('child')