Logic#
You may remember that in our first lab we came across boolean data:
type(True)
bool
type(False)
bool
True
and False
are reserved keywords that represent logical values.
Logical operators#
Back in lab 1, we became familiar with the basic mathematical operators: +
, -
, *
, /
, **
etc. Python also provides us with a suite of logical operators that evaluate whether a given expression is True
or False
.
The simplest example is the ==
operator:
5 == 5
True
5 == 6
False
This operator tests whether or not the values on either side are equal to one another. The examples above are somewhat trivial, but we could use the same syntax with variables:
a = 5
b = 6
c = a * b
c == 30
True
Warning
It is very easy to confuse the “equals to” operator ==
with the assignment operator =
, but they serve very different purposes. The =
operator assigns the value or the right hand side to the variable name on the left, whilst the ==
operator is comparing the values on either side to see whether or not they are equal to one another.
In short, a = 2
means “I am telling you that a
is equal to 2
”, whereas a == 2
means “Is a
equal to 2
?”
Rather than testing whether or not two values are equal to one another, we can also test the exact opposite: whether or not two values are not equal to one another:
5 != 6
True
5 != 5
False
A set of these comparitive operators can be found in the table below.
Condition |
Mathematical Notation |
Operator |
---|---|---|
Equals |
\(=\) |
|
Not equal to |
\(\neq\) |
|
Less than |
\(<\) |
|
Less than or equal to |
\(\le\) |
|
Greater than |
\(>\) |
|
Greater than or equal to |
\(\ge\) |
|
5 < 6
True
5 > 6
False
Just like the basic mathematical operations, these logical operators can cause errors if the types of the input data don’t make any sense:
5 <= 'ten'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[10], line 1
----> 1 5 <= 'ten'
TypeError: '<=' not supported between instances of 'int' and 'str'
Error
Here we get a TypeError because we are comparing an int
and a str
- we cannot compare the numerical value of an integer and a string!
In addition to the comparitive operators we have discussed so far, Python also allows us to test whether or not a given element can be found in a sequence:
'Fe' in ['Cr', 'Mn', 'Fe', 'Co', 'Ni']
True
The example above uses a list
, but we can also search for letters in a string:
'r' in 'Iron'
True
'f' in 'Iron'
False
To perform the opposite test, we can use not in
to see if a given element is not in a sequence:
'r' not in 'Iron'
False
'f' not in 'Iron'
True
and
and or
#
We now have the toolkit to evaluate basic logical statements:
favourite_colour = 'purple' # Assign 'purple' to favourite_colour
favourite_colour == 'red' # Evaluate whether or not favourite_colour equals 'red'
False
Notice the comments, this example highlights nicely the difference between the =
and ==
operators.
What if we want to combine logical operators? For example, what if we want to know whether a number is greater than 4, but less than 10? We already know how to test these two conditions separately:
number = 11
print(number > 4)
print(number < 10)
True
False
In this example, \(11\) is greater than \(4\), so the first expression evaluates to True
. \(11\) is also greater than \(10\) though, so the second expression evaluates to False
. To combine these two logical operators, we can use the and
keyword:
number > 4 and number < 10
False
Now we get a single bool
: False
. The and
keyword will only return True
if both of the expressions on either side also evaluate to True
. We have already seen that number < 10
is False
, hence the whole statement evaluates to False
.
Rather than and
we can also combine logical expressions with the or
keyword:
number > 4 or number < 10
True
Using the same expressions as before, we now find that by replacing and
with or
, the whole statement evaluates to True
. The or
keyword evalutes to True
if either expression on either side is True
.
We can summarise these new keywords with some very simple examples:
True and True
True
True and False
False
The and
keyword only evalutes to True
if both expressions either side of it are also True
.
True or True
True
True or False
True
False or False
False
The or
keyword evalutes to True
if either expression on either side of it are True
.
What if
?#
We now have the capability to test whether or not various expressions are True
or False
in Python - why should you care?
Imagine you’re playing a simple game with a friend. You think of a number between \(1\) and \(10000\), and then you ask your friend to try and guess that number. If your friend guesses correctly, you congratulate them on their frankly astonishing luck and joke that they might think about buying a lottery ticket. If your friend guesses incorrectly, you give them a pat on the back and wish them better luck the next time they play one of your silly games. Let’s code this up in Python.
my_number = 1298
success = 'Congratulations!'
failure = 'Better luck next time!'
Here we’ve declared most of the variables that we will need, the number
that you thought up in your head, and two responses: one for if your friend guesses correctly (success
) and one for if they fall short (failure
). Now let’s say our imaginary friend guesses 1298
:
friend_guess = 1298
We know how to verify if this guess is correct using logical operators:
friend_guess == my_number
True
Sure enough, my hypothetical friend’s luck is just wild. In this case, I want to print
the success
variable:
print(success)
Congratulations!
The decision making process we just went through manually can be written programmatically with an if
statement:
if friend_guess == my_number:
print(success)
Congratulations!
An if
statement can be used to make code conditional. In the example above, the success
variable is only printed if friend_guess
is equal to my_number
. This can be written generically as:
if this_expression_evaluates_to_true:
do_something
If the expression following the if
keyword evaluates to False
, then the code indented beneath will not run. If we want to specify what should happen in this case, we can use the else
keyword:
friend_guess = 2525
if friend_guess == my_number:
print(success)
else:
print(failure)
Better luck next time!
Here we have changed friend_guess
to a different number, so friend_guess == my_number
is now False
and print(success)
does not run. If the expression associated with an if
statement is False
, then the following else
block will run instead, here printing the failure
message.
Switching to a much less contrived example, sometimes we want to test more than one condition in an if
statement:
a = 25
if a < 30 and a % 5 == 0:
print(f'{a} is less than 30 and divisible by 5.')
25 is less than 30 and divisible by 5.
Reminder
The modulo operator %
computes the remainder after dividing one number by another.
We can do this, as shown above, by using the and
and or
keywords described previously. But what if we want to print
a different message if a
is less than \(30\) but not divisible by \(5\)?
a = 26
if a < 30 and a % 5 == 0:
print('25 is less than 30 and divisible by 5.')
elif a < 30:
print(f'{a} is less than 30 but not divisible by 5.')
26 is less than 30 but not divisible by 5.
Here we have introduced an elif
(“else-if”) statement. Our code firstly checks if a
is less than \(30\) and
divisible by \(5\). Failing that, we then perform a second check to see whether a
is less than \(30\). In this example, the statement after the elif
keyword evalutes to True
, so that block of code runs.
We can add an additional elif
block to account for another possibility:
a = 35
if a < 30 and a % 5 == 0:
print('25 is less than 30 and divisible by 5.')
elif a < 30:
print(f'{a} is less than 30 but not divisible by 5.')
elif a % 5 == 0:
print(f'{a} is greater than 30 but divisible by 5.')
35 is greater than 30 but divisible by 5.
And finally, we can add an else
block to cover the only other reasonable possibility:
a = 37
if a < 30 and a % 5 == 0:
print('25 is less than 30 and divisible by 5.')
elif a < 30:
print(f'{a} is less than 30 but not divisible by 5.')
elif a % 5 == 0:
print(f'{a} is greater than 30 but divisible by 5.')
else:
print(f'{a} is greater than 30 and is not divisible by 5.')
37 is greater than 30 and is not divisible by 5.
We are thus able to make our code run differently depending on the value of a
.
Exercise#
1.
a) Write a program that can tell whether or not a word has any vowels in it.
b) Extend your program by checking if the word contains no vowels and does not contain the letter t
.
2. Imagine that you are playing “Rock, Paper, Scissors” with a friend - they have (unbeknownst to you) picked rock.
Write some Python to decide who wins depending upon your weapon of choice.