Lecture 5: Conditionals and Boolean Logic¶
Welcome back! So far we've learned about variables, expressions, functions, and return values. Today we're going to learn how to make our programs make decisions using conditional statements. By the end of this lecture, you will be able to:
- understand boolean values and boolean expressions
- write conditional statements using
if,elif, andelse - combine conditions using logical operators
- use comparison operators to create boolean expressions
- familiarize with modulo and
randommodule for common conditional patterns
These skills will allow you to write programs that can make decisions based on different conditions!
Making Decisions in Code¶
So far, all our programs have executed every line of code in order. But what if we want our program to do different things depending on some condition?
Think about knitting patterns - sometimes the instructions say "if you're making the small size, knit 20 rows; if you're making the large size, knit 30 rows." Our programs need to make similar decisions.
In Python, we use conditional statements to control the flow of our program based on whether certain conditions are true or false.
Boolean Values¶
Before we dive into conditionals, we need to understand a new data type: boolean.
A boolean value can only be one of two things:
TrueFalse
Notice these start with capital letters - that's important in Python!
Boolean values are named after George Boole, a 19th century mathematician who invented Boolean algebra. They're fundamental to how computers work - remember that punch cards and binary (0s and 1s)? Boolean logic is at the heart of that.
# Boolean values
is_wool = True
is_polyester = False
print(is_wool)
print(type(is_wool))
True <class 'bool'>
Boolean Algebra via Logical Operators¶
Sometimes you need to check multiple conditions at once. Python provides three logical operators:
and- True if BOTH conditions are Trueor- True if AT LEAST ONE condition is Truenot- True if the condition is False (returns the opposite boolean value)
and and or are binary operators and not is a unary operator (given the number of operands they have).
The logical operators have math equivalents: conjunctions (∧), disjunctions (∨), and negations (¬). There are a few more complex operators, including exclusive or (XOR), and you can learn more about theorems about booleans in other courses like discrete mathematics.
Truth Tables¶
In computer science, especially if you start to learn about circuits design, you'll often use something called a "truth table", which basically shows True/False values for a given boolean expression. Why circuits? Because computers build on bits, and the circuits are essentially boolean operations on these bits realized as physical circuitry.
Let's see the truth tables for these logical operators to understand how they work more concretely:
and operator:
| A | B | A and B |
|---|---|--------|
| True | True | True |
| True | False | False |
| False | True | False |
| False | False | False |
or operator:
| A | B | A or B |
|---|---|--------|
| True | True | True |
| True | False | True |
| False | True | True |
| False | False | False |
not operator:
| A | not A |
|---|-------|
| True | False |
| False | True |
# Let's test these
print(True and True) # True
print(True and False) # False
print(True or False) # True
print(False or False) # False
print(not True) # False
print(not False) # True
True False True False False True
By default, the operator precedence is that not precedes and precedes or.
# NOT has higher precedence than AND and OR
has_umbrella = False
is_raining = True
# not is evaluated first!
print(not has_umbrella and is_raining)
True
# What will this print?
a = True
b = False
c = True
print(not a or b and c)
False
# What about this?
print((a or b) and c)
True
Comparison Operators¶
We can create boolean values by comparing things. Python has several comparison operators that evaluate to True or False:
==equal to (note: two equals signs!)!=not equal to<less than>greater than<=less than or equal to>=greater than or equal to
These operators create boolean expressions - expressions that evaluate to True or False.
# Comparing numbers
gauge_stitches = 18
target_stitches = 20
print(gauge_stitches == target_stitches) # False
print(gauge_stitches < target_stitches) # True
print(gauge_stitches != target_stitches) # True
False True True
Common mistake: Using a single = when you mean to compare. Remember:
x = 5assigns the value 5 to variable xx == 5compares x to 5 and returns True or False
# This is assignment, not comparison!
needles = 5
# This is comparison
needles == 5 # True
True
Composing Boolean Expressions¶
Now Let's see how we can build more complex boolean expressions using logical operators and comparison operators, and also the arithmetic operators we've seen before.
# Examples with and
temperature = 30
is_snowing = True
print(temperature < 32 and is_snowing) # True (both conditions are true)
print(temperature > 32 and is_snowing) # False (first condition is false)
True False
# Examples with or
day = "Saturday"
print(day == "Saturday" or day == "Sunday") # True (first condition is true)
True
# Examples with not
has_yarn = False
print(not has_yarn) # True (reverses False to True)
True
Note on Operator Precedence:¶
When you combine multiple operators in one expression, Python follows a specific order of operations. Understanding operator precedence helps you write correct boolean expressions.
Order from highest to lowest precedence:
- Parentheses
() - Arithmetic operators (
**,*,/,//,%,+,-) - Comparison operators (
<,<=,>,>=,==,!=) - Logical operators (
not,and,or)
# Arithmetic happens before comparison
x = 10
print(x + 5 > 12) # Same as (x + 5) > 12
# First: 10 + 5 = 15
# Then: 15 > 12 → True
True
# Python does the minimal
def add_one(x):
print("adding one")
return x + 1
print(x > 12 and add_one(x) > 10) # False
False
print(add_one(x) > 10 and x > 12) # False
adding one False
# Comparison happens before logical operators
temperature = 68
is_sunny = True
# These parentheses are optional but make it clearer
result = (temperature > 65) and is_sunny
print(result) # True
# Without parentheses is the same result!
result = temperature > 65 and is_sunny
print(result) # True
True True
Idiomatic Python¶
You can chain comparison operators in Python to form very natural looking math kind of statements.
x = 2.1
1 < x < 3 # True, equivalent of doing 1 < x and x < 3
True
This is not as natural like for a variable range (1 < x < 3) but this also works.
1 != x == 3 # False, equivalent of doing 1 != x and x == 3
False
Poll time!¶
What will happen when you print this?
x = 5
print(0 < x < 10 == True)
The if Statement¶
Now that we have done quite a bit of boolean operations, we're ready to construct conditional statements! Conditional statements basically are making decisions based on some boolean value. The simplest conditional is the if statement.
Syntax:
if condition:
# code to execute if condition is True
# (this is the if-block, note the indentation!)
If the condition evaluates to True, the indented code block runs. If it's False, the code block is skipped.
temperature = 65
if temperature < 70:
print("You might want a sweater!")
print("Have a nice day!") # This always prints
You might want a sweater! Have a nice day!
Notice the structure:
ifkeyword- A boolean expression (
temperature < 70) - A colon
: - An indented code block (just like functions!)
The indentation tells Python which statements are part of the if-block.
# Let's try with a different temperature
temperature = 75
if temperature < 70:
print("You might want a sweater!") # This won't print
print("Have a nice day!") # This still prints
Have a nice day!
Practice Time¶
Write a function that takes in temperature and prints the above sentences based on the temperature < 70 condition.
def print_greeting(temperature):
# TODO: replace pass with your code
pass
The else Statement¶
Often we want to do one thing if a condition is true, and something else if it's false. That's where else comes in.
Syntax:
if condition:
# code if condition is True
else:
# code if condition is False
machine_running = False
if machine_running:
print("Machine is running")
else: # this branch executes because the condition is False
print("Machine is not running")
Machine is not running
Think of if-else like a fork in the road: your program will take one path or the other, but never both.
# In knitting, you start from the side that's called the right side
# And after working through one row of stitches, you flip your piece
# and you are on the wrong side.
row_number = 5
if row_number % 2 == 0:
print(f"Row {row_number}: This is a wrong-side row (purl)")
else:
print(f"Row {row_number}: This is a right-side row (knit)")
Row 5: This is a right-side row (knit)
A note on the modulo operator¶
The modulo operator is perfect for creating repeating patterns and checking divisibility. For example, it's very useful to use modulo to check if a number is even or odd:
- If
n % 2 == 0, the number is even - If
n % 2 == 1, the number is odd
Similarly, it helps to check over where you are in a repeat, which is especially useful when we have knitting pattern repeats.
# Suppose a cable stitch group repeat in 8 stitches.
repeat_length = 8
num_stitch = 20
print(f"You are in repeat {num_stitch // repeat_length} "
f"on stitch {num_stitch % repeat_length}")
# Visually...
# xxxxyyyy xxxxyyyy xxxx
You are in repeat 2 on stitch 4
The elif Statement¶
What if you have more than two options? You could use multiple if-else statements, but there's a better way: elif (short for "else if").
Syntax:
if condition1:
# code if condition1 is True
elif condition2:
# code if condition1 is False AND condition2 is True
elif condition3:
# code if condition1 and condition2 are False AND condition3 is True
else:
# code if all conditions are False
You can have as many elif clauses as you need. The else at the end is optional.
yarn_weight = 3 # 1-7 scale (1=lace, 4=worsted, 7=jumbo)
if yarn_weight <= 2:
print("This is a fine yarn, use small needles")
elif yarn_weight <= 4:
print("This is a medium weight yarn")
elif yarn_weight <= 6:
print("This is a bulky yarn")
else:
print("This is a jumbo yarn, use large needles")
This is a medium weight yarn
Important: Python checks the conditions in order from top to bottom. Once it finds a True condition, it executes that block and skips the rest. This is different from having multiple separate if statements.
# elif: only ONE block executes
number = 10
if number > 5:
print("Greater than 5")
elif number > 8:
print("Greater than 8") # This won't print even though it's true!
Greater than 5
# Multiple ifs: BOTH blocks can execute
if number > 5:
print("Greater than 5")
if number > 8:
print("Greater than 8") # This WILL print
Greater than 5 Greater than 8
The random Module¶
Python's random module provides functions for generating random numbers. This is useful for simulations, games, or any time you need unpredictable values.
To use it, you need to import it first:
import random
# We can set a seed to make results reproducible
# (same seed = same sequence of "random" numbers)
random.seed(116)
What is random.seed()?
Computers can't generate truly random numbers. They use algorithms to create "pseudo-random" sequences. The seed is like a starting point for the algorithm. Using the same seed will produce the same sequence of "random" numbers, which is useful for:
- Debugging (you can reproduce the same "random" behavior)
- Testing (you can verify your code produces expected results)
In normal use, you wouldn't set a seed. Python would use the current time to generate different sequences each run.
Generating Random Integers¶
The random.randint(a, b) function returns a random integer between a and b (inclusive on both ends).
# Simulate rolling a six-sided die
die_roll = random.randint(1, 6)
print(f"You rolled a {die_roll}")
# Simulate a coin flip (0 or 1)
coin = random.randint(0, 1)
if coin == 0:
print("Heads")
else:
print("Tails")
You rolled a 6 Tails
Generating Random Floating-Point Numbers¶
The random.random() function returns a random floating-point number between 0.0 and 1.0 (not including 1.0).
# Generate a random decimal between 0 and 1
value = random.random()
print(f"Random value: {value}")
# We can use this for probability-based decisions
# For example, simulating a coin flip:
flip = random.random()
if flip < 0.5:
print("Heads")
else:
print("Tails")
Random value: 0.008729970103842355 Tails
Using Conditionals with Random Values¶
Random values become much more useful when combined with conditionals. Here's a more complete example:
def flip_coin():
"""
Simulate flipping a fair coin.
Returns "Heads" or "Tails".
"""
if random.random() < 0.5:
return "Heads"
else:
return "Tails"
# Flip the coin 10 times
print("Flipping a coin 10 times:")
for i in range(10):
result = flip_coin()
print(f"Flip {i+1}: {result}")
Flipping a coin 10 times: Flip 1: Tails Flip 2: Heads Flip 3: Heads Flip 4: Heads Flip 5: Heads Flip 6: Tails Flip 7: Tails Flip 8: Tails Flip 9: Heads Flip 10: Heads
Summary¶
Today we learned:
- Boolean values (
TrueandFalse) represent binary logic - Comparison operators (
==,!=,<,>,<=,>=) create boolean expressions - Logical operators (
and,or,not) combine boolean expressions - Conditional statements (
if,elif,else) let programs make decisions - Modulo operator (
%) gives remainders and is useful for patterns and divisibility randommodule generates random numbers:random.randint(a, b)for random integersrandom.random()for random decimals between 0 and 1
- Combining conditionals with random values for simulations and probability
These tools let you write programs that can make decisions and respond to different conditions!