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 firstTruevalue, if any. - For
or, the lastFalsevalue, if noTruevalues. - For
and, the firstFalsevalue, if any. - For
and, the lastTruevalue, if noFalsevalues.
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.
Python from scratch