Booleans & Comparisons

The Course
•
January 6, 2026
•
7 min read

Yesterday your programs ran straight through, top to bottom. Today they start making choices — and every choice comes down to one question: is this True or False?

Warm-up: from Day 1

Three quick ones before anything new. Try them without scrolling back to Day 1: pulling an idea out of memory is exactly what makes it stay there. Stuck for more than a minute? That’s worth knowing too — open the hint and carry on.

1. Predict all three lines, then run it.

Warm-up: predict Python
item = "  Notebook "
price = 3
print(f"[{item.strip()}]", price * 4)
print(20 // 6, 20 % 6)
print(type(20 / 5))
Check your prediction
[Notebook] 12
3 2
<class 'float'>

/ gives a float even when it divides evenly — 20 / 5 is 4.0.

2. Fix. This should print 1h 35m, and crashes instead.

Warm-up: fix Python
minutes = "95"
print(f"{minutes // 60}h {minutes % 60}m")
Check your fix
minutes = int("95")
print(f"{minutes // 60}h {minutes % 60}m")
1h 35m

"95" is text, and text can’t be floor-divided. Numbers that arrive as text — from input(), from a file — need converting before any arithmetic.

3. Write. A receipt total arrives as the text "$12.50". Print it with a 10% discount, to two decimal places: 11.25.

Warm-up: write Python
total = "$12.50"
Check your answer
total = "$12.50"
amount = float(total.replace("$", ""))
print(f"{amount * 0.9:.2f}")
11.25

Clean the text, convert it, then calculate: the same order as any messy input. total.strip("$") works too.

Comparison operators

Comparing values Python
print(3 < 5)
print(3 > 5)
print(3 <= 3)
print(3 == 3)      # equal to - two equals signs
print(3 != 3)      # not equal to

age = 20
print(age >= 18)
print(type(age >= 18))
= and == are different

= assigns a value; == asks a question. age = 18 sets the age. age == 18 checks it. Mixing them up is a rite of passage — Python catches it as a SyntaxError in an if, which is more than most languages do for you.

Comparisons work on strings too, alphabetically by character code:

Comparing text Python
print("apple" < "banana")
print("Zoe" < "adam")        # uppercase sorts before lowercase
print("apple" == "Apple")
print("apple".lower() == "Apple".lower())

# Python lets you chain comparisons, and it reads exactly as it looks.
score = 75
print(60 <= score < 90)

That last line is genuinely nice: 60 <= score < 90 is one expression, and score is evaluated once. Few languages allow it.

Combining conditions

and, or and not join conditions together. Python spells them as words, not symbols.

and, or, not Python
age = 25
has_ticket = True

print(age >= 18 and has_ticket)
print(age >= 65 or has_ticket)
print(not has_ticket)

# and requires both; or requires at least one.
print(True and False)
print(True or False)

# Parentheses make mixed expressions readable.
is_free = (age < 12) or (age >= 65)
print(f"Free entry: {is_free}")

and returns True only when both sides are true. or returns True when at least one is. not flips whatever it is given.

Truthiness

Every Python value can be treated as a condition, not just True and False. The rule is short: empty is false, everything else is true.

What counts as false Python
# These are all "falsy":
print(bool(0), bool(0.0), bool(""), bool([]), bool({}), bool(None))

# Everything else is "truthy":
print(bool(1), bool(-3), bool("hello"), bool(" "), bool([0]))

This is why you will see if name: rather than if name != "": in real Python. It reads as “if there is a name”, which is what you meant.

None is not False

None is Python’s “no value at all” — what a function returns when it returns nothing. It is falsy, but it is not False, and it is not 0. Test for it with is None, never with == None.

Short-circuiting

and and or stop as soon as the answer is settled. This is not a micro-optimisation — it is a tool for writing safe conditions.

The second half may never run Python
def loud(value):
    print("  (checked)", value)
    return value

print("First:")
result = loud(False) and loud(True)    # second call never happens

print("Second:")
result = loud(True) or loud(False)     # second call never happens

# Which is why this is safe even when the text is empty:
text = ""
print(len(text) > 0 and text[0] == "A")

Before you write your own

Predict. Four lines — the last one has a trap in it.

What will this print? Python
budget = 50
spent = 42
print(spent < budget)
print(spent == 42 and budget > 100)
print(not spent)
print(bool(""), bool("0"))
Check your prediction
True
False
False
False True

not spent is False because 42 is truthy. And "0" is a string with one character in it — not empty, so truthy — even though the number 0 is falsy.

Fix. This should print True on a Saturday or Sunday and False otherwise. It’s Monday. Run it: what comes out isn’t even True or False.

Is it the weekend? Python
day = "mon"
is_weekend = day == "sat" or "sun"
print(is_weekend)
Check your fix
day = "mon"
is_weekend = day == "sat" or day == "sun"
print(is_weekend)
False

Python read the original as (day == "sat") or "sun". The left side is False, so or moved on and gave back its right side — the string "sun", which is truthy. Each side of an or has to be a whole condition on its own.

Exercise

Password checker

Write a condition that decides whether a password is acceptable. It must be at least 8 characters long and contain a digit. Print True or False — for "hunter2000" that’s True. Then try "hunter2" and "hunterhunter", which should both print False, for different reasons.

any(c.isdigit() for c in password) tells you whether any character is a digit — you will understand that syntax fully on Day 4.

password = "hunter2000"

# Your code here
Hint 1: the idea

Two separate yes/no questions, joined by and: is it long enough? Does it contain a digit? Each question is one comparison you can write on its own line.

Hint 2: a first step

Answer the first question into a variable and print it: long_enough = len(password) >= 8. Then do the same for the digit check using the any(...) line above, and only then combine the two.

Show one solution
password = "hunter2000"

long_enough = len(password) >= 8
has_digit = any(c.isdigit() for c in password)

print(long_enough and has_digit)

Naming the two halves before combining them is worth the extra lines: the final condition then reads as a sentence rather than a puzzle.

What you learned

  • == != < > <= >= produce True or False; = assigns.
  • Comparisons chain: 0 <= x < 10.
  • and, or, not combine conditions, and they short-circuit.
  • Empty values are falsy; everything else is truthy.
  • None means “no value”; test it with is None.
Last updated on January 6, 2026

Was this article helpful?

Your response is saved on this device.