Conditions
Sometimes, often while looping, you only want to do things depending on something’s value. Specifying conditions like this is pretty simple in Python.
[1]:
pizzas = ["Pineapple", "Cheese", "Pepperoni", "Hot dog"]
for p in pizzas:
if p == "Cheese":
print("Nice pizza!")
elif p == "Pepperoni":
print("Amazing pizza!")
else:
print("Weird pizza.")
Weird pizza.
Nice pizza!
Amazing pizza!
Weird pizza.
Like the “body” of the for
loop, called a block, the block in the if
, elif
, and else
statements must be indented. The convention we adopt is to use four spaces for indentation.
The if
statement starts with if
(duh!) and what follows is a condition. If this condition isn’t met, the next elif
(for “else-if”) condition is evaluated. If this also isn’t met, the else
block is run. You can use as many elif
conditions as you like, or none at all, and the else
block is optional.
Python evaluates a condition and sees whether it is truth-like or not. If it is truth-like, the code in the block is run.
[2]:
if pizzas[0] == "Cheese":
print("It is cheese, my dudes.")
[3]:
pizzas[0] == "Cheese"
[3]:
False
[4]:
pizzas[1] == "Cheese"
[4]:
True
False
and True
are variables. They correspond to the possible values a boolean variable can have.
The result of a comparison is True
or False
, and we can perform comparisons using several operators, like ==
for equality, !=
for inequality, >
and <
for relative magnitude, and so on.
[5]:
True is False
[5]:
False
[6]:
True is not False
[6]:
True
[7]:
1 > 2
[7]:
False
[8]:
(1 > 2) is False
[8]:
True
This shows that we can combine comparison operators, just like with +
and friends. We can also use and
to require multiple conditions, or
to require at least one, and not
to negate a result.
[9]:
x = 2
[10]:
1 < x and x < 3
[10]:
True
[11]:
3 < x or 1 < x
[11]:
True
[12]:
not 1 < x
[12]:
False
Note that and
, or
and not
have lower precedence than >
, <
and ==
, but you can (and in general should) use parentheses to be more explicit.
Exercise
Play around with the booleans and try to answer the following! Can you do
double negotiations
convert a boolean to an integer
use parentheses to create a more complicated expression
Of course, we can compare everything we have played around with so far.
[13]:
x = [1, 2]
y = [1, 2]
z = {"hero": "thor"}
[14]:
x == y
[14]:
True
[15]:
y == z
[15]:
False
For collection objects like lists, tuples, and dictionaries, we can easily ask them if they contain something in particular using the in
operator.
[16]:
3 in x
[16]:
False
[17]:
2 in y
[17]:
True
[18]:
"thor" in z
[18]:
False
The last statement is False
because in
queries a dictionaries keys, not its values. This is useful if you want to access a key in a dictionary that might not exist:
[19]:
z["pizza"]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[19], line 1
----> 1 z["pizza"]
KeyError: 'pizza'
[20]:
if "pizza" in z:
print("We have pizza", z["pizza"])
else:
print("No pizza :(")
No pizza :(
Note that in
doesn’t dive into nested collections, but only looks at the top level.
[21]:
1 in [[1, 2], [3, 4]] # the elements are two lists
[21]:
False
[22]:
[1, 2] in [[1, 2], [3, 4]]
[22]:
True
Advanced (skip on first read)
Find the double-underscore method on lists and dictionaries that corresponds to the in
operator, and check that it does the same thing as the operator.
Solutions
Taking lists as an example, the dir
method can tell us what methods are available. The __contains__
method sounds promising.
[23]:
x = [1]
[24]:
x.__contains__(1)
[24]:
True
[25]:
x.__contains__(2)
[25]:
False
Strings work a lot like lists, which makes sense because they are effectively collections of single characters. This means we can also query string contents with in
.
[26]:
fact = "The best hero is Thor."
[27]:
"Thor" in fact
[27]:
True
[28]:
"Iron Man" in fact
[28]:
False
Truthiness
It’s conventional not to explicitly compare a condition to True
, because the if
statement already does that for us.
[29]:
if ("Pineapple" in pizzas) is True:
print("Weird.")
Weird.
[30]:
if "Pineapple" in pizzas:
print("Not weird.")
Not weird.
Likewise, rather than comparing for False, we just use not
.
[31]:
if ("Pineapple" in pizzas) is False:
print("Weird.")
[32]:
if "Pineapple" not in pizzas:
print("Not weird.")
[33]:
"Pineapple" not in pizzas # not ('Pineapple' in pizzas)
[33]:
False
[34]:
"Pineapple" not in pizzas
[34]:
False
The last two lines show that we can use not in
for checking that something is not in a collection. This reads more naturally.
All Python objects are truth-like unless they are the value False
, the value None
, or are empty collections (such as ""
, []
, ()
, {}
).
[35]:
if list() or dict() or tuple() or "":
print("You won’t see me!")
The value None
, which is available as the variable named None
, is often used as placeholder for an empty value.
[36]:
favourite = None
for p in pizzas:
if "Olives" in p:
favourite = p
[37]:
if favourite:
print(f"Found favourite: {favourite}")
else:
print("No favourite :(")
No favourite :(
It behaves as false-y value in conditions.
Conditions in loops
for
loops and comprehensions are the most common ways of iterating in Python. We’ve already seen that using conditions in these can be useful.
[38]:
not_cheesy = [p for p in pizzas if "cheese" not in p.lower()]
not_cheesy
[38]:
['Pineapple', 'Pepperoni', 'Hot dog']
Another way of iterating is with while
.
[39]:
i = 5
while i > 0:
print(f"T-minus {i} seconds")
# Equivalent to `i = i - 1`
i -= 1
print("Blast off!")
T-minus 5 seconds
T-minus 4 seconds
T-minus 3 seconds
T-minus 2 seconds
T-minus 1 seconds
Blast off!
The while
loop checks the condition, runs the block, and then re-checks the condition. If we don’t do something in the loop to change the result of the condition, we will end up looping forever!
You can uncomment and run the below, you may need to stop the kernel manually with the stop button.
[40]:
# i = 5
# while i > 0:
# print('All work and no play makes Jack a dull boy')
Because we do not change the value of i
in the loop, the condition always evaluates to True
, so we’re stuck. You can stop Python running the code by typing the Ctrl-c
key combination.
Sometimes you want to stop iterating when some condition is met. You could achieve this with a while
loop.
[41]:
ok = False
i = 0
while not ok:
ok = "cheese" in pizzas[i].lower()
# Equivalent to `i = i + 1`
i += 1
[42]:
i
[42]:
2
[43]:
pizzas[i - 1]
[43]:
'Cheese'
It is not nice to have to keep track of these ok
and i
variables. Instead, we can use a for
loop, which feels much more natural when iterating over a collection, and break
to stop looping (we can also use a break with a while
loop).
[44]:
for pizza in pizzas:
if "cheese" in pizza.lower():
yum = pizza
break
[45]:
yum
[45]:
'Cheese'
[ ]:
[ ]: