Booleans in Python (Part 1)

Translating from pseudocode

Translating from pseudocode to Python syntax seems pretty straightforward. We capitalize True and False but not or, and, and not. For example, running the code

print(True or False)
print(True and False)
print(not False)

gives the output

True
False
True

In Python, True and False are built-in Boolean constants, just like 1, 2, and 3 are built-in numerical constants.

Running the code

print("True")
print(True)
print(type("True"))
print(type(True))

gives the output

True
True
<class 'str'>
<class 'bool'>

Although True looks exactly like the string “True” when displayed by Python, the value True is not a string.

This makes translating from pseudocode to Python very straightforward, as long as we avoid quotation marks:

PseudocodePython
TrueTrue
FalseFalse
oror
andand
notnot

Caution

Do not use quotation marks on Booleans True and False.


Comparisons

Translation of comparisons from pseudocode also seems straightforward. If we try to check equality using a single equals sign, we will get the cryptic syntax error that tells us that “keyword can't be an expression”: running the code

print("True" = True)

gives the error

Traceback (most recent call last):
  File "<string>", line 1
SyntaxError: keyword can't be an expression

Since a single equals sign means assignment, two equals signs are used to check equality. For example, running the code

print("True" == True)

gives the output Flase.

We can also check for inequality. For example, running the code

print("True" != True)

gives the output True.


The other types of comparisons look like the ones in pseudocode, but they behave a little differently. You can use a sequence of comparisons on a sequence of values. The entire expression is true if the comparison between each consecutive pair is true. For example, running the code

print(3 < 4 < 5)
print(3 <= 4 < 2)
print(3 == 3 >= 3)

gives the output

True
False
True

The second expression is False because 4 < 2 is false. But that isn't the only way that the comparisons are a little surprising. We can also use them to compare strings. For example, running the code

print("A" != "a")
print("ape" <= "cat")
print("cat" == "cat ")

gives the output

True
True
False

There isn't anything too surprising here: we know that uppercase and lowercase letters are different, that words can be ordered like in a dictionary, and that a string is not the same as the same string with an extra blank space.


But what if we compare these two strings "cat" and "Cat"? Running the code print("cat" < "Cat") gives the output False. This answer is less obvious. We'll get back to it in a moment.

In this table, the only new information is how to check inequality and two new ways of making comparisons with is and is not.

FunctionPseudocodePython
<< <
>> >
<=<=
>=>=
= == ==
Not applicable!=
Not applicableNot applicableis
Not applicableNot applicableis not

We haven't yet talked about is and is not, but will do so later. We have also seen the following:

  • Multiple comparisons can be make on one line.
  • Strings can be compared.

Caution

Using is and is not may give unexpected answers.

You're welcome to investigate is and is not, which determine whether or not values have the same memory address, but be prepared not to yet understand what is going on.


Python's approach to Booleans

So, let's see what happens when we put together some Boolean expressions. What if we want to check if a number is between 10 and 20? We can join two smaller expressions using and or use multiple comparisons on one line:

num = 10

print((10 <= num) and (num <= 20))
print(10 <= num <= 20)

Both give the correct answer:

True
True

To check if a person is eligible for a discount based on age, we use or to join a smaller expression that checks for ages less than 21 and a smaller expression that checks for ages greater than 65:

age = 35

print((age < 21) or (65 < age))

The result is False, as it should be.


Now get ready for some surprises. Running the code

print("False" and "True")

gives the output True. Based on our understanding of data types, and should require Booleans. Since False and True with quotations marks are strings, we should get an error message. But we don't. Moreover, the answers doesn't seem to make any sense. If the strings are being interpreted as Booleans, why isn't the answer False? How about running the code

print("cat" or "dog")

Will we get an error message now? Strangely, no. The output is cat. It looks like we can use or on non-Booleans. Then, can we use Booleans in places where non-Booleans are usually used? It seems so. Running the code

print(True + 4)

gives the output 5. What is going on?

Non-Booleans masquerading as Booleans:

False:
None, False, 0, 0.0, ""
True:
Almost everything else

The problem is that Python is very accommodating and flexible. Almost all values are given the Boolean value True, even if the values themselves are not Booleans. A few values are False, including None, False itself, 0, 0.0, and the empty string. Later we'll see a few other False values, empty like the empty string.

When we wrote cat or dog, the answer was true, since cat and dog are both True.

Caution

Avoid using Boolean functions on non-Boolean values.

Booleans masquerading as numbers: False can be 0 and True can be 1. You've probably guessed that Python is also being flexible by giving True and False numerical values when you try to add them.

Caution

Avoid using mathematical functions on Boolean values.


Strings and character encodings

Now let's look more deeply into the result of comparing the strings cat and Cat. The ordering used in comparison is based on code points in Unicode.

Unicode is an international standard for encoding.
It maps each character to a number (code point).

In this encoding standard, each character is assigned a distinct number. When the order of two strings is determined, these numbers are used for comparisons. Here's a partial listing of codepoints:

  32! 33" 34# 35$ 36
0  481 492 503 514 52
0  481 492 503 514 52
A  65B 66C 67D 68E 69
a  97b 98c 99d100e101

But don't worry about the exact numbers. It is the order that is useful to know: the blank space, punctuation, the digits in order, the upper-case letters in order, and the lower-case letters in order. There are many other characters that are encoded as well, but we're not going to worry much about those.

There are built-in functions that determine the code point given a character and that determine the character given a code point:

FunctionPython
Code point from characterord('A')
Character from code pointchr(65)

More string functions

There are other functions for Booleans. Here I'll just mention some of the string functions:

FunctionPython
Letter.isalpha()
Lower case.islower()
Upper case.isupper()
Number.isdigit()
Blank.isspace()

These will be handy when we write programs to encrypt strings, as they allow us to check properties of each character. In particular, isalpha() returns True if the character is a letter, with islower() and isupper() being more specific, checking for lower case or upper case. We can also check for numbers and blanks.

Caution

Use dot notation.

Notice that these all use dot notation, so be sure to put the function names after the input, joined by a period. For example, "My string".isalpha().

Caution

Use only on strings.

Remember that these functions only work on strings.