🎯 Learning Objectives
- Understand the
booltype and its two values:TrueandFalse - Combine conditions with logical operators:
and,or,not - Understand short-circuit evaluation and how Python uses it
- Distinguish
==(equality) fromis(identity) - Know which values are truthy vs falsy
- Use boolean expressions in real-world validation patterns
The bool Type
Python's boolean type has exactly two values: True and False
(always capitalised). Booleans are the result of comparisons and conditions — they're
the foundation of all decision-making in code.
is_active = True
is_admin = False
print(type(is_active)) # <class 'bool'>
# bool is a subclass of int!
print(True + True) # 2
print(False * 100) # 0
print(int(True)) # 1
print(int(False)) # 0
bool_basics.py
bool is a subclass of int in Python. True is
literally 1 and False is 0. This means you can
use booleans in arithmetic — useful for counting how many conditions are True.
Comparison Operators
We saw these in Lesson 04. Here's the full set — each returns a bool:
| Operator | Meaning | Example | Result |
|---|---|---|---|
== | Equal to | "hi" == "hi" | True |
!= | Not equal to | 5 != 3 | True |
< | Less than | 3 < 5 | True |
> | Greater than | 5 > 5 | False |
<= | Less than or equal | 5 <= 5 | True |
>= | Greater than or equal | 7 >= 3 | True |
age = 25
print(age == 25) # True
print(age != 30) # True
print(age >= 18) # True
# Chained comparisons
print(18 <= age < 65) # True — "working age"
print(0 < age < 18) # False
# Strings compare lexicographically (dictionary order)
print("apple" < "banana") # True
print("Zebra" < "apple") # True (uppercase < lowercase in ASCII)
comparisons.py
Logical Operators: and, or, not
Logical operators combine boolean expressions:
| Operator | Meaning | Returns True when… |
|---|---|---|
and | Logical AND | Both sides are True |
or | Logical OR | At least one side is True |
not | Logical NOT | The operand is False |
age = 25
has_license = True
is_banned = False
# and — both must be True
can_drive = age >= 16 and has_license
print(can_drive) # True
# or — at least one must be True
gets_discount = age < 12 or age >= 65
print(gets_discount) # False
# not — flips the boolean
is_allowed = not is_banned
print(is_allowed) # True
# Combining all three
can_enter = (age >= 18 or has_license) and not is_banned
print(can_enter) # True
logical_ops.py
Truth tables
| A | B | A and B | A or B | not A |
|---|---|---|---|---|
| True | True | True | True | False |
| True | False | False | True | False |
| False | True | False | True | True |
| False | False | False | False | True |
not binds tightest, then and, then or.
When in doubt, use parentheses: (a or b) and c is clearer than relying on precedence.
Short-Circuit Evaluation
Python's and and or are short-circuit
operators — they stop evaluating as soon as the result is determined:
andstops at the first falsy value (if everything is truthy, returns the last).orstops at the first truthy value (if everything is falsy, returns the last).
# and — returns first falsy, or last value if all truthy
print(1 and 2 and 3) # 3 (all truthy → last value)
print(1 and 0 and 3) # 0 (first falsy)
print("" and "hello") # "" (first falsy)
# or — returns first truthy, or last value if all falsy
print(0 or "" or "hi") # "hi" (first truthy)
print(0 or "" or []) # [] (all falsy → last value)
# Practical: default values
name = user_input or "Anonymous"
# If user_input is empty/None/falsy, use "Anonymous"
short_circuit.py
and / or don't always return True or
False — they return the actual value that determined the result.
This is why 0 or "default" returns "default", not True.
False and print("hello") — the print() never runs because
and already knows the result is falsy.
Identity (is) vs Equality (==)
These are two fundamentally different checks:
| Operator | Checks | Question it answers |
|---|---|---|
== | Equality (value) | Do these have the same value? |
is | Identity (memory) | Are these the exact same object? |
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True — same value
print(a is b) # False — different objects in memory
print(a is c) # True — c points to the same object as a
# Use 'is' only for singletons: None, True, False
x = None
print(x is None) # ✓ correct
print(x == None) # works but discouraged by PEP 8
identity.py
== for everything except checking
None. Use is None / is not None for None checks.
Truthy & Falsy Values
Every Python object can be evaluated as a boolean. These values are falsy:
| Falsy Value | Type |
|---|---|
False | bool |
None | NoneType |
0, 0.0, 0j | int / float / complex |
"" (empty string) | str |
[] (empty list) | list |
() (empty tuple) | tuple |
{} (empty dict) | dict |
set() (empty set) | set |
Everything else is truthy — any non-zero number, non-empty container, or object.
# Pythonic: use truthiness directly
items = []
# Don't do this:
if len(items) == 0:
print("Empty")
# Do this instead:
if not items:
print("Empty")
# Check if a string has content
name = "Alice"
if name:
print(f"Hello, {name}")
# Check if a value exists
result = None
if result is None:
print("No result yet")
truthy_falsy.py
if items: instead of
if len(items) > 0:. This is shorter, faster, and more Pythonic.
Practical Boolean Patterns
# Pattern 1: Validation
def is_valid_age(age):
return isinstance(age, int) and 0 <= age <= 150
# Pattern 2: Default with 'or'
username = input("Username: ") or "guest"
# Pattern 3: Guard clause with 'and'
# Only access .name if user is not None
display = user and user.name
# Pattern 4: Counting True values
scores = [85, 92, 45, 78, 61, 33]
passing = sum(s >= 60 for s in scores)
print(f"{passing} students passed") # 4
# Pattern 5: all() and any()
numbers = [2, 4, 6, 8]
print(all(n % 2 == 0 for n in numbers)) # True — all even
print(any(n > 7 for n in numbers)) # True — at least one > 7
patterns.py
Primary source: Python Docs — Truth Value Testing
Ask your AI tutor! Confused about when and returns a
value vs a boolean? Unsure why [] is [] is False?
These subtleties matter — ask and get clarity.
💻 Exercises
Write a script that checks if a user can access a resource. They need to be: at least 18 years old AND (a member OR an admin). Test with several combinations and print the result.
Show solution
age = 25
is_member = True
is_admin = False
can_access = age >= 18 and (is_member or is_admin)
print(f"Access granted: {can_access}") # True
# Test: under 18
age = 16
can_access = age >= 18 and (is_member or is_admin)
print(f"Access granted: {can_access}") # False
# Test: 18+ but neither member nor admin
age = 30
is_member = False
is_admin = False
can_access = age >= 18 and (is_member or is_admin)
print(f"Access granted: {can_access}") # False
Create a list of 10 different values (mix of numbers, strings, lists, None, booleans).
Loop through them and print whether each is truthy or falsy using bool().
Show solution
values = [0, 1, "", "hello", [], [1, 2], None, True, False, 0.0]
for val in values:
label = "truthy" if bool(val) else "falsy"
print(f"{str(val):>10} → {label}")
# Output:
# 0 → falsy
# 1 → truthy
# → falsy
# hello → truthy
# [] → falsy
# [1, 2] → truthy
# None → falsy
# True → truthy
# False → falsy
# 0.0 → falsy
Write a password strength checker. A password is "strong" if it meets all
of these: at least 8 characters, contains at least one digit, and contains at least
one uppercase letter. Use any() and string methods.
Show solution
password = "Hello123"
long_enough = len(password) >= 8
has_digit = any(c.isdigit() for c in password)
has_upper = any(c.isupper() for c in password)
is_strong = long_enough and has_digit and has_upper
print(f"Password: {password}")
print(f"Strong: {is_strong}") # True
# Weak example
password2 = "hello"
long_enough = len(password2) >= 8
has_digit = any(c.isdigit() for c in password2)
has_upper = any(c.isupper() for c in password2)
is_strong = long_enough and has_digit and has_upper
print(f"\nPassword: {password2}")
print(f"Strong: {is_strong}") # False