Module 3 · Control Flow & Logic ⏱ 14 min

Boolean Logic & Operators

By the end of this lesson you will be able to:
  • Evaluate expressions with comparison operators (==, !=, <, >, <=, >=)
  • Combine boolean expressions with and, or, and not
  • Predict the truth value of chained comparisons like 1 < x < 10

Every useful program makes decisions by asking questions. Is this number big enough? Did the user type the right password? Is this score a new record? These questions are answered with boolean logic — expressions that come out as either True or False, the two values of Python's bool type.

Comparison operators ask a question about two values and hand back a boolean:

print(5 > 3)      # True
print(10 == 10)   # True
print(4 != 4)     # False

The six operators are == (equal), != (not equal), < (less), > (greater), <=, and >=. Notice that equality testing is ==, with two equals signs — a single = assigns a value and never asks a question. Mixing those up is the first mistake every beginner makes.

flowchart LR
  A["age >= 10"] --> C{"and"}
  B["height >= 120"] --> C
  C --> D["can ride"]
  style C fill:#3776ab,color:#fff
Logical operators combine simple comparisons into bigger decisions.

Combine questions with and, or, not

Real decisions rarely hinge on one question. Logical operators stitch smaller booleans into bigger ones:

  • andTrue only when both sides are True
  • orTrue when at least one side is True
  • not — flips True to False and False back to True

So age >= 10 and height >= 120 is True only when a rider clears both bars, while has_ticket or is_staff lets in anyone holding either credential. Reach for not when you want to invert a condition you already wrote the easy way around.

Comparisons, logical operators, and a chained comparison — press Run.
x = 7
print(x > 5 and x < 10)
print(x == 3 or x == 7)
print(not x > 10)
print(1 < x < 10)

Chained comparisons

Python lets you write a range check the way you would say it out loud: 1 < x < 10 means "x is between 1 and 10, endpoints excluded." Under the hood that expands to 1 < x and x < 10, so both halves have to hold for the whole thing to be True.

Swap to <= and the endpoints are inclusive: 1 <= x <= 10 keeps 1 and 10 as well. Most languages force you to write the two comparisons and join them yourself; Python's chaining is just a friendlier spelling of the same test.

flowchart TD
  Q["a and b"] --> T{"is a falsy?"}
  T -->|"yes"| F["result is a (b never runs)"]
  T -->|"no"| E["result is b"]
  style F fill:#b45309,color:#fff
  style E fill:#3776ab,color:#fff
Short-circuit: and stops the moment it sees a falsy value; the right side never runs.

Short-circuit: the right side may never run

and and or do something subtle — they stop as soon as the answer is certain. If the left side of an and is already False, the right side cannot rescue it, so Python skips it entirely. If the left side of an or is already True, the right side is likewise ignored.

That behaviour is more than a speed trick. Because or hands back the first truthy value it sees, user_name or "guest" becomes a tidy default: use the real name when there is one, otherwise fall back to "guest". Just remember that 0 and empty strings are falsy, so score or "no score" also fires when score is a perfectly valid zero.

'or' as a default, and short-circuiting in action. Watch what the right side contributes.
# 'or' returns its first truthy value, which makes a tidy default
user_name = ""
display_name = user_name or "guest"
print(display_name)        # guest - the empty string is falsy

score = 0
print(score or "no score")  # no score - but 0 is a valid score, so beware!

# 'and' and 'or' short-circuit: the right side only runs if it could matter
print(0 and "never seen")   # 0 - right side skipped because 0 is falsy
print(7 or "ignored")       # 7 - right side skipped because 7 is truthy
Exercise

Write can_ride(age, height) that returns True only when age is at least 10 and height is at least 120.

def can_ride(age, height):
    # return True if age >= 10 and height >= 120
    pass
Exercise

What does this print? Predict all three lines, then Check.

a = 7
b = 3
print(a > 5 and b > 5)
print(a > 5 or b > 5)
print(not a == 7)
Exercise

This is_big(n) is meant to return True when n is greater than 100. Instead it compares the number to True directly, which quietly fails for most values. Fix it so it returns the right boolean.

def is_big(n):
    # meant to be True when n is greater than 100
    return n == True
Exercise

A shop gives a discount when a member's cart is at least 50 or anyone's cart is at least 100. Write can_discount(is_member, cart_total) that returns the right boolean. Mind which condition is wrapped in parentheses.

def can_discount(is_member, cart_total):
    # True for members spending 50+, or anyone spending 100+
    pass

Recap

  • Six comparison operators ask questions; remember == tests equality while = assigns.
  • Combine conditions with and (both must hold), or (either holds), and not (invert one).
  • Chain comparisons naturally: 1 <= x <= 10 keeps the endpoints.
  • and and or short-circuit — they stop the moment the answer is decided, which makes value or default a clean idiom for fallbacks.
  • Test truthiness with if x:, never with if x == True:.

Next you will put these conditions to work inside if / else branches that choose what your program does next.

Checkpoint quiz

What does 5 > 3 and 2 > 4 evaluate to?

Which expression correctly checks whether x is between 1 and 10 (inclusive)?

Go deeper — technical resources