Booleans in Python (Part 2)
Example: checking for a vowel
Let's write some Boolean functions. As our first example, let's write a function that determines if a character is a vowel. To match the names of the built-in Python functions, we'll call it is_vowel
and we'll choose a parameter name that reminds us that the input should be a single character.
def is_vowel(char):
is_a = char == "a" or "A"
is_e = char == "e" or "E"
is_i = char == "i" or "I"
is_o = char == "o" or "O"
is_u = char == "u" or "U"
return is_a or is_e or is_i or is_o or is_u
Since there are 10 characters to check, let's break it up into separate lines for the sake of readability.
print(is_vowel("a"))
We can now try out the function on a vowel, which gives the correct answer, True, on running the program.
print(is_vowel("b"))
We can also try it on a consonant, which gives a confusing answer, A, on running the program. What happened?
We will use the technique of tracing the code to see what values were computed.
Definition
To trace code is to figure out values step by step.
Let's look a little more closely at the first line:
def is_vowel(char):
is_a = char == "a" or "A"
is_e = char == "e" or "E"
is_i = char == "i" or "I"
is_o = char == "o" or "O"
is_u = char == "u" or "U"
return is_a or is_e or is_i or is_o or is_u
The variable is_a
is assigned the or
of two expressions. The first expression is char == "a"
. This has the value False
. The second expression is the string consisting of "A"
. Since it has the value True
, is_a
has the value "A"
. Similarly, each of the following variables were assigned values:
is_a = "A"
is_e = "E"
is_i = "I"
is_o = "O"
is_u = "U"
Since Python uses short-cut evaluation, in the final expression it only needed to read the first value, determine it had Boolean value True
, and then stop:
return "A" or "E" or "I" or "O" or "U"
It returned the last and only value it read.
Revisiting expressions using non-Booleans
Let's take a look at how Python handles expressions with non-Booleans. Due to short-cut evaluation, as soon as the computer sees a value with the Boolean value True
, like 1, it returns the True
value. For example, running the code
print(0 or 1 or 0)
outputs 1.
Consider the following code:
print(0 or 0 or "")
This outputs the empty string ""
. All of these values are False
, but the computer can't conclude that the condition is False
until it sees them all. So it returns the last False
value it reads, namely the empty string.
Put in another way, the computer returns the first True
value it finds, like in the following code and its output, or the last False
one if all are False
, as in the previous case: the code
print(0 or 0 or "not zero")
outputs not zero.
With and
, short-cut evaluation means returning the first False
value that is found, or the last True
value if all are True
. So when the code
print("True" and 0 and "False")
is run, 0 is returned. When the code
print("True" and "True" and "spaghetti")
is run, we get the output spaghetti because it is the last of three True
values.
All of the values are examined in the example code
print("True" and "True" and 0)
giving the output 0. The last value in the expression is the first False
value found.
We're now ready to revisit the use of the strings True
and False
with the Boolean functions or
and and
. Let's consider the following code
print("True" or "False")
print("False" or "True")
print("False" and "True")
print("True" and "False")
which outputs the following:
True False True False
In the first two examples, the first value is returned since short-cut or returns the first True
value, if any. In the last two examples, the last value is returned since short-cut and returns the last True
value if there are no False
values. Now we can see what happened when we made our error in the function is_vowel()
: the first True
value was returned, since the code
print("a" == "a" or "A")
print("b" == "a" or "A")
gives the output
True A
Short-cut evaluation returns:
- For
or
, the firstTrue
value, if any. - For
or
, the lastFalse
value, if noTrue
values. - For
and
, the firstFalse
value, if any. - For
and
, the lastTrue
value, if noFalse
values.
Keep this in mind if funny answers occur. In a True
expression, or
returns the first value with Boolean value True
and otherwise the last False
value. In a False
expression, and
returns the first value with Boolean value False
and otherwise the last True
value.
Checking for a vowel, corrected
We can now fix our function to include the correct expressions, namely comparing the input to a lower case vowel and comparing the input to an upper case vowel:
def is_vowel(char):
is_a = char == "a" or char == "A"
is_e = char == "e" or char == "E"
is_i = char == "i" or char == "I"
is_o = char == "o" or char == "O"
is_u = char == "u" or char == "U"
return is_a or is_e or is_i or is_o or is_u
Caution
Not all uses of or
and and
in English translate well into code.
This is an easy mistake to make, since we would say “Is the input a lower case a
or an upper case A
?” Double-check any code you write that seems like a straightforward translation from English and make sure it fits what the computer will understand.
Glimpse of the future
More succinct solutions exist.
Later we'll see other shorter ways of writing this function.
Example: checking for a consonant
What if we want to write a function that checks if a character is a consonant? If we use the same method as for checking a vowel, we'll have 42 characters to check - that's a lot of writing to do! Why not use is_vowel
instead?
def is_consonant(char):
return not is_vowel(char)
Does this work for all strings? No, since we could have numbers or symbols. What about the following code?
def is_consonant(char):
return char.isalpha() and not is_vowel(char)
What if we have a string of length more than one? The following code works if the input is a string, but not if it could be any input:
def is_consonant(char):
return len(char) == 1 and \
char.isalpha() and not is_vowel(char)
Caution
When using not
, be sure what all the possibilities are.
You can think of not
as splitting the universe into “those for which this is true” and “those for which it is not true”. You need to understand what the universe is to be sure that you obtain the behaviour you want.