# 3 Boolean Comparisons, Boolean Operators, and Expressions

# Notebook 3 - Boolean Comparisons, Boolean Operators, and Expressions¶

**You can make your own copy of this notebook by selecting File->Save a copy in Drive from the menu bar above.**

Things you'll learn in this lesson:

- More about types in Python
- Comparison operators
- Boolean operators
- How to combine values, variables, and operators into expressions

## More Data Types¶

In Python, values have a *type*. We already saw three data types in the previous lesson (ints, floats, and strings). In this lesson we'll learn about some additional types, how to determine a variable's type, how to convert a value from one type to another, and how to combine values, variables, and operators into complex expressions.

### The Boolean (`bool`

) Type¶

Python supports a special type called booleans, written `bool`

in Python, which are used to indicate whether something is true or false. Booleans have one of two possible values:

`True`

`False`

When evaluating a **number** as a boolean, the following rules apply:

- 0 is
`False`

- 0.0 is
`False`

- all other numerical values are
`True`

When evaluating a **string** as a boolean, the following rules apply:

- the empty string (
`""`

and`''`

) is`False`

- all other strings are
`True`

Marc’s Law of Boolean Evaluation in Python: **“nothingness is false, somethingness is true”**

### The None Type¶

Python has a special type called `None`

and it means *no value*.

It's a good choice when you want to initialize a variable without an obvious choice for the initial value, like this:

`name = None`

None always evaluates to False in boolean expressions.

### Type Conversion and the `type`

Function¶

### Type Conversion Functions¶

These are built-in Python functions to convert from one type to another. The name of the function mirrors the type you want to convert to, and you pass a variable or value to be converted.

`int(x)`

- converts*x*to an integer`float(x)`

- converts*x*to a floating point number`str(x)`

- converts*x*to a string`bool(x)`

- converts*x*to a boolean value

### When do you need to convert a type?¶

When you have an expression containing mixed types...

`name + number`

`age * 365`

When you call a function that requires a different type than you are passing. For example, the `len`

function returns the length of a string so it expects the value passed to it will be a string.

`print(len(42))`

won’t work, but...

`print(len(str(42)))`

is fine. Try both of those experiments in the code cell below.

```
```

Here's an example where type conversion is needed:

```
birth_year = input("Enter the year you were born:")
age = 2024 - birth_year
print(f"You are {age} years old")
```

Try running this code in the following cell and, when it fails, see if you can fix it.

```
birth_year = input("Enter the year you were born:")
age = 2024 - birth_year
print(f"You are {age} years old")
```

### The type() function¶

The built-in `type`

function returns the type of the passed value. It conveys the type name in a string of the form `<class type-name>`

. Don't worry too much for now about that format - just know that the name after `class`

is the type name.

```
>>> type(123)
<class 'int'>
```

Run the next cell to see the `type`

function in action.

```
type_int = type(123)
type_float = type(3.14)
type_str = type("a string")
type_bool = type(True)
type_none = type(None)
```print(type_int, type_float, type_str, type_bool, type_none)

```
s = input("enter your age: ")
print(type(s))
```

## Comparison Operators¶

As their name suggests, comparison operators allow us to compare values and result in a boolean type indicating whether the comparison is `True`

or `False`

.

The following table summarizes the most commonly used operators in Python, along with their definition when applied to numbers and strings.

operator | operation on numbers | operation on strings |
---|---|---|

== | equal to | equal to |

!= | not equal to | not equal to |

> | greater than | lexicographically greater than |

>= | greater than or equal to | lexocographically greater than or equal to |

< | less than | lexicographically less than |

<= | less than or equal to | lexocographically less than or equal to |

### Challenge¶

Which boolean value (`True`

or `False`

) do each of these expressions evaluate to?

`123 == 10`

`10 == 123`

`123 == 123`

`123 != 321`

`123 != 123`

`age == 64`

`"andrew" == "marc"`

`"marc" == "andrew"`

`"marc" == "marc"`

`"marc" != "Marc"`

`>`

and `>=`

¶

`123 > 10`

`10 > 123`

`123 > 123`

`123 >= 123`

`age >= 65`

`age > min_age`

`"fred" > "marc"`

`"marc" > "fred"`

`"marc" >= "marc"`

`"marc" > "Marc"`

## Boolean Operators - `and`

, `or`

, and `not`

¶

Boolean operators are special operators in Python that let you combine boolean values in logical ways corresponding to how we combine truth values in the real world. An example of a boolean **and** expression would be "I'll buy a new phone if I like the features **and** the price is low". There are three main boolean operators: `and`

, `or`

, and `not`

. We'll look at examples of each in the next cells.

### Boolean `and`

¶

`A and B`

is `True`

only true when both A and B are `True`

, otherwise it's `False`

.

Example:

- I ride my bike only when it's both sunny and warm.
- In other words, if
`is_sunny`

and`is_warm`

are both`True`

then I**will**ride my bike.

In Python...

```
if is_sunny and is_warm:
print("ride bike")
```

We haven't learn about `if`

statements so don't worry if the previous construct looks unfamiliar. It's a simple way of checking the value of a boolean expression, but we'll dive deeper into `if`

statements in our next lesson.

```
is_sunny = False
is_warm = False
print(is_sunny and is_warm)
```

##### Truth Table for boolean `and`

¶

`var1` |
`var2` |
`var1 and var2` |
---|---|---|

`False` |
`False` |
`False` |

`True` |
`False` |
`False` |

`False` |
`True` |
`False` |

`True` |
`True` |
`True` |

### Boolean `or`

¶

`A or B`

is `True`

when either A or B are `True`

, or when both are `True`

, otherwise it's `False`

.

Example:

- I ride my bike when it's sunny, warm, or both.
- In other words, if
`is_sunny`

or`is_warm`

(or both) are`True`

then I**will**ride my bike.

In Python...

```
if is_sunny or is_warm:
print("ride bike")
```

#### Truth Table for boolean `or`

¶

`var1` |
`var2` |
`var1 or var2` |
---|---|---|

`False` |
`False` |
`False` |

`True` |
`False` |
`True` |

`False` |
`True` |
`True` |

`True` |
`True` |
`True` |

#### Truth Table for boolean `not`

¶

`var1` |
`not var1` |
---|---|

`False` |
`True` |

`True` |
`False` |

```
is_rainy = False
is_warm = True
```if not is_rainy and is_warm:
print(“ride bike”)
else:
print(“don’t ride today”)

## Expressions¶

- Python lets us combine values, variables, and operators into larger units called expressions.
- When evaluating an expression, Python internally replaces the variable names with the values to which they refer.
- Expressions appear in many places, for example:
- numerical calculations
`2 + 2`

- assignment statements
`age = age + 1 # we do this every birthday`

- function calls
`print(age * 365) # number of days alive`

- numerical calculations
- As we learn more, we'll see expressions popping up all over the place.

#### Challenge¶

Let's combine `input`

, `print`

, and expressions to build a temperature conversion program. The formulae for converting Celcius to Fahrenheit and vice versa are:

`F = (C + 32) * 9/5`

`C = (F - 32) * 5/9`

```
degrees_f = float(input('Enter number of degrees in fahrenheit: '))
# Add an assignment statement that computes degrees_c as a function of degrees_f
print(f'{degrees_f}°F = {degrees_c}°C')
```

```
degrees_c = input('Enter number of degrees celsius: ')
# Add an assignment statement that computes degrees_f as a function of degrees_c
print(f'{degrees_c}°C= {degrees_f}°F')
```

### Types of Expressions¶

- arithmetic expressions

`tax = income * tax_rate`

- comparative expressions

`error_count <= 0`

- boolean expressions

`more_to_do and no_errors`

- combinations of the above

`valid_ticket and (cur_day - purchase_day) < exp_window`

### Order of Evaluation¶

How does Python know the correct order to evaluate a complex expression?

Example: `4 + 1 * 5`

Is that `(4 + 1) * 5`

, which is `25`

?

Or is it `4 + (1 * 5)`

, which is `9`

?

Another example: True or False and False

Is that `(True or False) and False`

, which is `False`

?

Or is it `True or (False and False)`

, which is `True`

?

Python uses operator precedence rules to avoid this ambiguity and evaluate expressions in a predictable way.

### Simplified Python Precedence Rules¶

This is a subset of the complete rules (in order of highest to lowest precedence):

- parentheses (innermost to outermost, left to right)
- exponentiation (left to right)
- multiplication, division, modulus (left to right)
- addition, subtraction (left to right)
- comparisons (left to right)
- boolean not
- boolean and
- boolean or

### Practical Advice¶

Marc's rule or operator precedence: **When in doubt, use parentheses.**

I make liberal use of parentheses because then:

- I don't need to remember the precedence rules.
- I don't have to worry about surprises.
- It makes my code more readable.

For example, I could write this expression, which evaluates `A and B`

first, then `C and D`

, and finally takes the boolean `or`

of the two preceding results:

`A and B or C and D`

but I much prefer to make this explicit so I don't have to think about precedence rules every time I look at this code:

`(A and B) or (C and D)`

## Challenges¶

Evaluate the following expressions mentally, then verify your answers in the following code cell...

`2 + 3 * 4 + 5`

`(2 + 3) * (4 + 5)`

`1 * 2 + 3 * 4 + 5 * 6`

`100 / 25 / 2`

`(100 / 33) <= 3`

`(100 // 33) <= 3`

`True and False and True`

`True and True or False and False`

`100 % 99`

`(100 / 100) // (100 % 100)`

```
print(2 + 3 * 4 + 5)
print((2 + 3) * (4 + 5))
print(1 * 2 + 3 * 4 + 5 * 6)
print(100 / 25 / 2)
print((100 / 33) <= 3)
print((100 // 33) <= 3)
print(True and False and True)
print(True and True or False and False)
print(100 % 99)
print((100 / 100) // (100 % 100))
```

Assuming we have the following variables and functions:

`customer_id`

- unique identifier per customer`customer_age`

- customer age in years`active_marketing_campaign`

-`True`

if we're allowed to start a new marketing campaign and`False`

otherwise`purchased(customer_id)`

- returns`True`

if this customer already bought the product and`False`

otherwise

Run the following cell to initialize three variables.

```
customer_id = 987
customer_age = 49
active_marketing_campaign = True
```

Your marketing department wants to start a new campaign. Formulate an expression to determine whether it's ok to start a new marketing campaign.

```
```

Marketing says you're allowed to offer the discount to adults only. Formulate an expression to determine whether it's ok to start a marketing campaign and the customer is 18 years of age or older.

```
```

Marketing says you're bothering too many people with this promotion. Refine the previous boolean expression by excluding people who've already purchased the product.

```
```

Write a `print`

statement to verify the previous expression results in the expected type using a built-in function.

Assume you have the following variables:

`birth_year`

- year customer was born**in a string**`cur_year`

- current year**in a string**

Formulate an arithmetic expression to calculate and print the customer's current age.

```
```