= True
condition1 = False
condition2 and condition2 condition1
False
Upon completion of this lesson you should:
Boolean variables (i.e. True
and False
) can be used in conjuction with Python’s built-in keywords and
, or
and not
to evaluate logical statements, which can be used to control the flow of a program (i.e. if x
is True
do one thing, otherwise to something else). These keywords have a direct connection to the English words we already use for logic:
Here we use the and
keyword to see if both are true, which they are not:
= True
condition1 = False
condition2 and condition2 condition1
False
Using the or
keyword we can see if either are true, which is the case:
= True
condition1 = False
condition2 or condition2 condition1
True
And we can use the not
word to essentially reverse the value of condition2
. not condition2
is equivalent to saying not False
, which means True
.
= True
condition1 = False
condition2 1and not condition2 condition1
not
to condition2
, and then evalulates the and
comparison. If we are ever unsure we can use parentheses (i.e. (not condition2)
).
True
The interaction between and
, or
and not
can be expressed more formally using a truth table:
cold | windy | cold and windy | cold or windy | (not cold) and windy | not (cold and windy) |
True | True | True | True | False | False |
True | False | False | True | False | True |
False | True | False | True | True | True |
False | False | False | False | False | True |
English does not have word for “one or the other but not both”. The closest might be “either”, but this could also be taken to mean both. Instead we had to create a new technical term: “exclusive or”, which is sometimes denoted as “xor”. Table 4.1 does not include any columns for this. This would be (cold and not windy) or (windy and not cold)
, which is quite verbose. Sadly, cold xor windy
is not valid Python.
Probably the most releavant value of bools
for engineers is comparing numerical values to some condition using relational comparisons such as “less than” (<
) and “greater than” (>
). The symbols we use for these were presented in Table 2.2, but they are repeated below for convenience:
Symbol | Operation |
---|---|
> |
Greater than |
< |
Less than |
>= |
Greater than or equal to |
<= |
Less than or equal to |
== |
Equal to |
!= |
Not equal to |
Consider the case where we have some value
and some threshold limit
which we want the value stay below:
= 4.3
value = 5.0
limit < limit value
True
We can also combine comparisons, such as ensuring our value is between an upper and lower limit:
= 4.3
value = 2.0
lower_limit = 5.0
upper_limit > lower_limit) and (value < upper_limit) (value
True
Using brackets is always a good idea to avoid mistakes and also make it easier to read later. However, Python allows for the following way to ensure a value is between limits, which matches how we would write this:
= 1.3
value = 2.0
lower_limit = 5.0
upper_limit < value < upper_limit lower_limit
False
And lastly, we can add an =
sign to our <
and >
to get “less/more than or equal to” if the situation calls for it:
= 2.0
value = 2.0
lower_limit = 5.0
upper_limit <= value <= upper_limit lower_limit
True
Another useful application of relational comparisons is to determine the type of a variable. We have already seen that a given operator (i.e. +
) means different things depending on the variables involved. When we write more complicated programs we will probably need to do some “type-checking” ourselves. This can be done as follows:
= 1
a 1= type(a) == int
check print("The result is", check)
int
as a keyword instead of int()
the function. We can think of int()
as a function that converts a given value to the type of int
.
The result is True
Checking the type is quite important in Python because the freedom that Python provides, in terms of conversion between types, can also create problems if we are not careful. This is sometimes called a “foot gun” because it allows us to “shoot ourselves in the foot”, which is an expression for hurting yourself by accident.
Now that we have seen how to generate True
and False
values using conditional comparisons, we need a way to use them. All programming languages include if-else statements. In Python the syntax is as follows:
if
is a built-in keyword
:
The solution is acidic
But what happens if the solution is basic?
= 8.0
pH if pH < 7.0:
print('The solution is acidic')
1if pH > 7.0:
print('The solution is basic')
if
to catch the case of basic pH.
The solution is basic
The above code is not very efficient because both statements will be evaluated even though only one of them can be true. Small inefficiencies like this can cause problems in 2 ways.
Remedying the inefficient code is so important that Python has a built-in keyword for this: elif
.
= 8.0
pH if pH < 7.0:
print('The solution is acidic')
1elif pH > 7.0:
print('The solution is basic')
elif
is another built-in keyword that is short for “else if”, where “else” means more like “otherwise”.
The solution is basic
In the above version, only one of the above print statements is executed. Importantly, if the first if
statement is True
, the second elif
statement is not even checked. Python executes these statements in order and stops as soon as it finds a condition that is satisfied. This behavior is illustrated in Figure 4.1.
if
and elif
statements. The flow on the right is more efficient since it skips the second check if the first one is satisfied.
You have probably noticed that the above logic is incomplete. What if the solution is neutral?
= 7.0
pH if pH < 7.0:
print('The solution is acidic')
elif pH > 7.0:
print('The solution is basic')
1else:
print('The solution is neutral')
else
is also a built-in keyword.
The solution is neutral
Note that the else
statement does not actually check to see if the pH is 7.0. It just assumes that if the program reached this point then 7.0 is the only possibility remaining. This behavior is why writing a program is sometimes like solving a puzzle.
Let’s rewrite the logic to assume nothing:
= 7.0
pH if pH < 7.0:
print('The solution is acidic')
elif pH > 7.0:
print('The solution is basic')
elif pH == 7.0:
print('The solution is neutral')
else:
print('The pH value is invalid')
The solution is neutral
For-loops were introduced in the last chapter, but we will take another look. We can include if-statements inside for-loops:
= [25.0, 25.6, 29.0, 31.9, 32.5, 28.0] # degrees C
temperature = [0, 1, 2, 3, 4, 5] # hours
time for i in range(len(time)):
if temperature[i] > 30.0:
print('The temperature exceeded 30C at', time[i], 'hours')
The temperature exceeded 30C at 3 hours
The temperature exceeded 30C at 4 hours
We can also exit a for-loop early if some condition is met. For instance, if we want to find the first occurence of a value:
= [25.0, 25.6, 29.0, 31.9, 32.5, 28.0] # degrees C
temperature = [0, 1, 2, 3, 4, 5] # hours
time for i in range(len(time)):
if temperature[i] > 30.0:
= time[i]
t 1break
print("The temperature first exceeded 30C at", t, "hours")
break
is another built-in keyword in Python. It does more or less what the work means: it breaks out of the loop and ends it.
The temperature first exceeded 30C at 3 hours
While-loops have nearly the same purpose as for-loops except they can potentially run forever instead of iterating over a fixed set of items.
i
in this case.
ctrl-c
at the Python console to stop a running process.
0
1
2
3
We can also put the condition inside the while-loop to get more complicated logic:
= True
keep_running = 0
i = 3
j while keep_running:
= i + 1
i = j + 1
j if (i > 5):
= False
keep_running print("i has exceeded the limit")
elif (j > 5):
= False
keep_running print("j has exceeded the limit")
j has exceeded the limit
You might also use a while-loop when the dataset you’re analyzing can change size during processing. This can happen if you are deleting items after they are processed, then you would stop with the length of the list is 0. This is explored in Example 4.2.
Python prides itself on being easy to read. Typically this means using as few lines as possible. It is possible to write simple if-statements on a single line as follows:
= 5
a = True if a > 0 else False
result print("Result:", result)
Result: True
In keeping with Python’s desire to be ‘readable’ this syntax is almost self explanatory. We will revisit this trick when we talk about writing Pythonic code.
and
and or
Technically it is possible to have pH < 0 and pH > 14, it just means extremely acid or basic. Let’s add more categorizations to catch these:
= 17.0
pH 1if (pH >= 0.0) and (pH < 7.0):
print('The solution is acidic')
elif (pH > 7.0) and (pH <= 14.0):
print('The solution is basic')
elif pH == 7.0:
print('The solution is neutral')
elif pH < 0:
print('The solution is extremely acidic')
elif pH > 14:
print('The solution is extremely basic')
else:
2print('This statement will never print')
and
keyword to combine the results of both the bracketed statements. They both need to be True
(i.e. True and True
) for this check to be selected.
else
to catch unplanned conditions is good practice.
The solution is extremely basic
all()
and any()
The list of Python built-in functions (Table B.1) contains any()
and all()
. These are used for evaluating the conditions for an entire data container, instead of just a single value. Let’s take a closer look:
= [True, True, False]
container = any(container)
any_true print("Result:", any_true)
Result: True
At least one of the items in container
is True
, so any()
evaluates to True
.
= [True, True, False]
container = all(container)
all_true print("Result:", all_true)
Result: False
But not all of the items are True
, so all()
returns False
.
Unfortunately, this does not work on a list of numerical values the way we might wish. all()
checks if things are True
, not on the numerical values. In fact, all numerical values other than 0
are considered True
. (Remember that True -> 1
and False -> 0
).
= [1, 2, -4, 6]
a = all(a)
all_true print("Result:", all_true)
Result: True
“Truthy” is a word that computer programmers made up to describe something that evaluates to True
or False
. An example is the fact that any nonzero number is intepreted as True
. The None
data type also has a “Truthiness” and is considered False
. The empty string ''
is also considered False
.
So to use the all()
and any()
functions on a list of data we must first evaluate each item:
= [1.0, 12.5, 2.8, 8.8]
pHs 1= pHs.copy()
temp 2for i in range(len(pHs)):
3= pHs[i] < 7
pHs[i] 4= all(pHs)
all_true print("Result:", all_true)
pHs
so that we have a place to record the True
/False
values
pHs
all()
Result: False
Note that there is no none()
function. This can be accomplished using not any()
. If even one item in a collection is True
then any()
will return True
, then the not
will reverse this to a False
.
in
a CollectionBecause Python strives to be “readable” by humans, it offers several tricks or shortcuts. We have already seen the use of the in
keyword when iterating over a collection in a for-loop. However, it can also be used as follows:
= [1, 2, 5, 6]
a = 3 in a
check print("Result:", check)
Result: False
The power of this is well illustrated by revisiting the function we wrote in Example 4.1. Using the in
keyword we could reduce that rather verbose code to the following:
def length_v2(x):
if type(x) in (int, float, bool, complex):
= 1
L elif type(x) in (list, dict, tuple, set, str):
= len(x)
L else:
= 0
L return L
Now we have checked for all the single data types and all the container types with just a few lines. And moreover, verbally reading this code makes it quite clear what is happening.
Copy and paste the following code to a new .py
file in Spyder and work through each cell until you get the desired result.
# %% Problem 1: Using Logical Operators
# Given the variables `a = True`, `b = False`, and `c = True`:
# a. Use the `and` operator to check if both `a` and `c` are True.
# b. Use the `or` operator to check if either `a` or `b` is True.
# c. Use the `not` operator to negate the value of `b`.
#
# Fill in the code below:
= True
a = False
b = True
c
=
a_and_b =
a_and_c =
a_or_b =
not_b
print("Result of a and b:", a_and_b)
print("Result of a and c:", a_and_c)
print("Result of a or b", a_or_b)
print("Result of not b:", a_or_b)
# %% Problem 2: Using Relational Operators
# Given the variables `x = 10` and `y = 20`:
# a. Use the `>` operator to check if `x` is greater than `y`.
# b. Use the `<=` operator to check if `x` is less than or equal to `y`.
# c. Use the `==` operator to check if `x` is equal to 10.
#
# Fill in the code below:
= 10
x = 20
y
=
is_greater =
is_less_equal =
is_equal
print("Is x greater than y?", is_greater)
print("Is x less than or equal to y?", is_less_equal)
print("Is x equal to 10?", is_equal)
# %% Problem 3: Boolean Logic with Collections
# Given the list `numbers = [5, 8, 12, 16, 23]`:
# a. Use a loop and an `if` statement to check if all elements in the list are greater than 0.
# b. Use a loop to check if there is at least one element in the list that is divisible by 4.
#
# Hint: Use "break"
# Ex:
# for ...
# if ....
# .....
# break
#
# Fill in the code below:
= [5, 8, 12, 16, 23]
numbers
# Check if all elements are greater than 0
= True
all_positive for num in numbers:
pass
# Check if at least one element is divisible by 4
= False
has_divisible_by_4 for num in numbers:
pass
print("Are all numbers positive?", all_positive)
print("Is there a number divisible by 4?", has_divisible_by_4)
# %% Problem 4: Using Boolean Logic in If/Else Blocks
# Write a program that asks the user for their age and checks:
# a. If the age is less than 18, print "Minor".
# b. If the age is between 18 and 65, print "Adult".
# c. If the age is 65 or older, print "Senior".
#
# Fill in the code below:
= int(input("Enter your age: "))
age
if :
pass
elif:
pass
else:
pass
# %% Problem 5: Logical Operators in Complex Conditions
# Given the variables `temperature = 25` and `is_raining = False`:
# a. Use an `if` statement to print "Nice weather" if the temperature is between 20 and 30 (inclusive) and it's not raining.
# b. Otherwise, print "Not a good day for a walk."
#
# Test to see that this works for different combinations of temperature and is_raining
= int(input("What is the temperature in celsius?"))
temperature = False
is_raining
# write your code here
# %% Problem: Using Elif Statements
#
# Write a program that asks the user to input their exam score (0-100) and:
# a. If the score is 90 or above, print "A".
# b. If the score is between 80 and 89, print "B".
# c. If the score is between 70 and 79, print "C".
# d. If the score is between 60 and 69, print "D".
# e. If the score is below 60, print "F".
#
# Fill in the code below:
= int(input("Enter your exam score (0-100): "))
score
if score >= 90:
print("A")
elif:
pass
elif:
pass
elif:
pass
else:
pass
# %% Problem 7: Using `all()` and `any()` with Lists
# Given the list `marks = [70, 85, 90, 76, 65]`:
# a. Use the `all()` function to check if all marks are 60 or above.
# b. Use the `any()` function to check if any mark is 90 or above.
#
# Note: An example that checks if all marks are integers is shown
#
# Fill in the code below:
= [70, 85, 90, 76, 65]
marks
= all(type(mark) == int for mark in marks)
all_ints = all()
all_passed = any()
has_top_score
print("All marks are 60 or above:", all_passed)
print("There is a mark 90 or above:", has_top_score)
# %% Problem 8: Using While Loops with If Statements
#
# Write a program that repeatedly asks the user to input a number.
# a. If the number is negative, stop the loop and print "Loop stopped".
# b. If the number is positive, print the number and continue asking.
#
# Fill in the code below:
while True:
= int(input("Enter a number (negative to stop): "))
number
if number < 0:
print("Loop stopped")
break # Exit the loop if the number is negative
else:
print("You entered:", number)