Lesson A6 – Conditions¶
In this part of the tutorial we learn about what is True
and False
in Python. Testing if a certain condition is fulfilled, is a vital element of programming.
Emtpy type¶
In the context of conditions and testing them, it is also nice to have a representation for an absent value in the sense of an “unset” or “no-value” value. In Python there is a specific data type for an empty value, which is called None
.
[1]:
# None
n = None
print(type(n))
<class 'NoneType'>
None is not nothing but a full-fledged exiting object. None can be passed to and returned by functions.
Boolean values¶
A boolean variable is a data type which can assume only one of two values: True
or False
.
[2]:
# boolean
b = True
print(type(b))
<class 'bool'>
Other data types can be converted into boolean data types with the bool()
function, e.g. the integer 1 is converted to True while the integer 0 is converted to False. You can even convert strings to booleans. In fact every defined, non-empty object evaluates to True. None
as an empty-value evaluates to False.
[3]:
print(bool(1))
print(bool(0))
print(bool("False"))
print(bool(None))
True
False
True
False
Advanced¶
Because of this relation we can also kind of calculate with boolean values.
[4]:
print(True * False)
print(True + True)
print(True + True * False)
0
2
1
Empty collections evaluate to False as well.
[5]:
list_empty = []
print(bool(list_empty))
False
Comparison operators¶
True and False play an important role, when you want to test for certain conditions. You can compare things with the bit-wise operators summarised in the table below.
Operator |
Meaning |
---|---|
|
True, if |
|
True, if |
|
True, if |
|
True, if |
|
True, if |
|
True, if |
|
True, if |
|
True, if |
|
True, if |
Note, that the “equal”-operator is ==
instead of just =
since a single equal sign is already used for variable assignments.
[6]:
print(1 == 1) # equal?
print(1 != 1) # not equal?
True
False
[7]:
print("True?", 2 > 1)
# 2 greater than 1?
print("True AND True?", (1 < 2) & (2 > 1))
# 1 less than 2 AND 2 greater than 1?
print("True AND True?", 1 < 2 > 1)
# 1 less than 2 AND 2 greater than 1? (Python short hand notation)
print("True AND/OR True?", (1 > 2) | (2 > 1))
# 1 greater than 2 AND/OR 2 greater than 1? (At least one statement True)
print("True AND/OR True?", (1 < 2) | (2 > 1))
# 1 less than 2 AND/OR 2 greater than 1? (At least one statement True)
print("True XOR True?", (1 > 2) ^ (2 > 1))
# 1 greater than 2 OR 2 greater than 1? (Only one statement True)
print("True XOR True?", (1 < 2) ^ (2 > 1))
# 1 less than 2 OR 2 greater than 1? (Only one statement True)
True? True
True AND True? True
True AND True? True
True AND/OR True? True
True AND/OR True? True
True XOR True? True
True XOR True? False
These bit-wise operators have their literal expressions summarised in the table below which can be used instead. But be aware, that they do not always have the same meaning (see subsection Advanced below).
Operator |
Meaning |
---|---|
|
True, if |
|
True, if |
|
True, if |
|
True, if |
[8]:
print("True AND True?", (1 < 2) and (2 > 1))
print("True OR True?", (1 > 2) or (2 > 1))
True AND True? True
True OR True? True
Advanced¶
The is
operator¶
The literal is
operator has a different meaning than the ==
operator.
[9]:
a = 1
b = 1
print(a is b) # identical?
print(a is not b) # not identical?
True
False
But …
[10]:
a = 450
b = 450
print(a is b) # equal?
print(a is not b) # not equal?
False
True
While ==
tests for value equality, is
tests for object identity. Due to the way Python handles the storage of integer values for example, a stored 1 is always the same object, which is true for a few other integers, too. A stored 450 on the other hand is only equal to another 450 by value but it is not the same object.
Note, while bool(None)
evaluates to False, None is neither equal to False, nor is it the same object.
[11]:
print(None is None)
print(True is True)
print(False is False)
print(None is False)
print(None is True)
True
True
True
False
False
[12]:
print(None == None)
print(True == True)
print(False == False)
print(None == False)
print(None == True)
True
True
True
False
False
On the other hand, True and False are equal to 1 and 0 by value (but are different object of course).
[13]:
print(True == 1)
print(False == 0)
True
True
[14]:
print(True is 1)
print(False is 0)
False
False
The and
and or
operator¶
The and
and or
operator may also not work as you expect so be careful:
[15]:
print(1 and 2)
print(2 and 1)
# If True return the last True value (not True)
2
1
[16]:
print(1 and 0)
print(0 and 1)
print(None and 0)
# If False return the first False value (not False)
0
0
None
[17]:
print(1 or 2)
print(2 or 1)
# If True return the first True value (not True)
1
2
[18]:
print(None or 0)
print(0 or None)
# If False return the last value (not True)
0
None
The in
operator¶
In Python there is additionally a literal comparison operator stating if an object is part of another one: the in
operator. It can be for example used to discover if an object is contained in a container.
[19]:
1 in [1]
[19]:
True
If and else¶
So for now we can write straightforward programs as a series of statements that are executed one after the other. We get more flexibility in our code, when we test for conditions and do different things, depending on the outcome of the test. We can do this in Python using the if
directive. Note, that the code block following the statement with the if
directive is indented by 4 spaces. In this way Python knows, that this code block is subordinate and only to be executed if the if
statement evaluates to True.
[20]:
a = 1
if a == 1: # <- colon after the conditional statement
print("a is really equal to one")
a is really equal to one
Note: We had our first encounter here with something very essential to Python: indention. So far we used indention only for cosmetic reasons. Now that we use a directive that introduces some hierarchy of statements in our code, we need to make sure that the subordinate statements are indented. You need the same indention policy throughout your whole program. By convention indention is done by 4 spaces per hierarchy level.
We can extend this with the else
directive.
[21]:
a = "Hello, World!"
# Test if the first character of the string `a` is not equal to "X"
if a[0] != "X":
print(a)
else:
print("I cannot work with this ...")
Hello, World!
We can test also for several conditions, one by one with the elif
directive.
[22]:
a = ["aspirin", "ethanol"]
# Test if the string "aspirin" is an element of the list `a`
if "aspirin" in a:
print("I can use this")
# Otherwise test if the string "ethonal" is an element of the list `a`
elif "ethanol" in a:
print("Ok, than I will use this")
# Otherwise ...
else:
print("I cannot work with this ...")
I can use this
Advanced¶
Try and except¶
Using if
and else
to test if something is True and than act accordingly seems like a reasonable procedure to write programs that can deal with varying situations. With this “asking for permission first before you do something”-approach, you are often on the safe side. It is typical to Python that it also allows you to do it the other way round. In many cases, it can be better just to try something you want to do, and only act accordingly if something goes wrong. This is particularly nice
if you are checking a condition that is true most of the time and leads to an exception if it is not. The magic words here are try
and except
.
[23]:
a = [1, 2, 3]
# Try to append a value to the list `a`
try:
a.append(4)
# And if this does not work ... (but it does!)
except AttributeError():
pass # Do nothing
print(a)
[1, 2, 3, 4]
[24]:
a = (1, 2, 3)
# Try to append a value to the tuple `a`
try:
a.append(4)
# And if this does not work ... (and it doesn't!)
except AttributeError:
print("I cannot work with this ...")
print(a)
I cannot work with this ...
(1, 2, 3)
You can additionally use the else
and the finally
directive to extend this.
[25]:
a = [1, 2, 3]
try:
# Let's see if this works ...
a.append(4)
except AttributeError:
# Aha, it did not ...
print("I cannot work with this ...")
else:
# Yes, it worked!
print("Appended 4 to a")
finally:
# No matter if it worked ...
print(a)
Appended 4 to a
[1, 2, 3, 4]
This can seem a bit more complex at first compared to the if-else variant because you need to anticipate which kind of error would be raised, if what you try to do fails. But depending on the individual case, the try-except variant can be also easier to understand. In any case it is a good thing that we can tackle conditional program execution from different angles. The if-else code of the last example could look like this by the way:
[26]:
a = [1, 2, 3]
# Let's see if this works ...
if isinstance(a, list):
# Yes, it will work!
a.append(4)
print("Appended 4 to a")
else:
# Aha, it will not ...
print("I cannot work with this ...")
# No matter if it worked ...
print(a)
Appended 4 to a
[1, 2, 3, 4]
Note: The isinstance(object, type)
function is the preferred way of saying type(object) is type
.