Booleans & Truthiness
Reviewed & published by Brayan K
Truthiness is Python's rule that every value is treated as either "truthy" or "falsy" in a boolean context, so any object — not just True and False — can control an if or while.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Understanding which values count as falsy, and how and/or actually behave, unlocks some of the cleanest, most readable patterns in the language.
What You'll Learn in This Lesson
- True / False and the bool() function
- The complete list of falsy values
- Writing 'if items:' instead of 'if len(items) > 0:'
- How and / or return an operand (short-circuit)
- Setting defaults with 'x or fallback'
- Checking collections with any() and all()
1 bool() and the Falsy Values
Pass any object to bool() and Python tells you whether it's truthy or falsy. There's a short, fixed list of falsy things — everything else is truthy:
# The falsy values
print(bool(False)) # False
print(bool(None)) # False
print(bool(0)) # False (also 0.0)
print(bool("")) # False (empty string)
print(bool([])) # False (empty list)
print(bool({})) # False (empty dict)
# Everything else is truthy
print(bool(1)) # True
print(bool(-5)) # True (any non-zero number)
print(bool("0")) # True (a non-empty string!)
print(bool([0])) # True (a list with one item)# Test the truthiness of different values
values = [0, 1, "", "hi", [], [1], None, "0"]
for v in values:
print(repr(v), "->", bool(v))
# ✅ Expected output:
# 0 -> False
# 1 -> True
# '' -> False
# 'hi' -> True
# [] -> False
# [1] -> True
# None -> False
# '0' -> True✅ Truthiness in if Statements
Because empty collections are falsy, you can test them directly. This is more readable and more idiomatic than comparing lengths:
cart = []
# The Pythonic way
if cart:
print("Checkout", len(cart), "items")
else:
print("Your cart is empty") # this runs
# Works for strings too
name = ""
if not name:
print("Please enter a name") # this runs
# Compare: the clunky, non-idiomatic version
if len(cart) > 0: # works, but verbose
print("has items")Prefer if cart: over if len(cart) > 0: and if not name: over if name == "":. Shorter, clearer, and it works for every kind of collection.
2 and / or Return Operands (Short-Circuit)
This surprises newcomers: and and or don't return True/False — they return one of the actual operands, and they stop early ("short-circuit") as soon as the answer is known:
# 'or' returns the first TRUTHY operand (or the last one)
print(0 or "fallback") # 'fallback'
print("Ada" or "Guest") # 'Ada' -> stops at the first truthy
print(0 or "" or "last") # 'last'
# 'and' returns the first FALSY operand (or the last one)
print("a" and "b") # 'b' -> both truthy, returns the last
print(0 and "b") # 0 -> stops at the first falsy
# Common default pattern
username = ""
display = username or "Anonymous"
print(display) # 'Anonymous'# and / or return operands and short-circuit
def get_name(raw):
# If raw is empty/None, fall back to a default
return raw or "Anonymous"
print(get_name("Grace")) # Grace
print(get_name("")) # Anonymous
print(get_name(None)) # Anonymous
# Short-circuit avoids an error: the right side is skipped
data = None
print(data and data["key"]) # None -> never indexes None
# 'and' returns the last value when all are truthy
print(1 and 2 and 3) # 3
# ✅ Expected output:
# Grace
# Anonymous
# Anonymous
# None
# 3🧩 Checking Many Items with any() & all()
any() asks "is at least one truthy?" and all() asks "are they all truthy?". Pair them with a generator expression for clean validation:
scores = [85, 92, 78, 90]
# Are ALL scores passing (>= 60)?
print(all(s >= 60 for s in scores)) # True
# Is ANY score perfect (== 100)?
print(any(s == 100 for s in scores)) # False
# Validate a form: every field filled?
fields = ["Ada", "ada@x.com", ""]
print(all(fields)) # False ('' is falsy)
# The empty-iterable edge cases
print(any([])) # False -> nothing is truthy
print(all([])) # True -> nothing failsall([]) being True reads as "no item broke the rule", and any([]) being False reads as "no item satisfied it". Keep that edge case in mind for empty inputs.
🎯 Your Turn: Fill in the Blanks
Replace each ___ with any, all, or, or not so the output matches.
# 🎯 YOUR TURN: replace each ___ to match the expected output
ages = [25, 17, 40, 30]
name = ""
# 1. Is EVERYONE an adult (>= 18)? -> False
print(___(a >= 18 for a in ages))
# 2. Is ANYONE a minor (< 18)? -> True
print(___(a < 18 for a in ages))
# 3. Give a default name -> 'Guest'
print(name ___ "Guest")
# 4. Is the name missing? -> True
print(___ name)
# Expected output:
# False
# True
# Guest
# Trueprint(all(a >= 18 for a in ages)) # False
print(any(a < 18 for a in ages)) # True
print(name or "Guest") # Guest
print(not name) # TrueCommon Errors & How to Fix Them
❌ Assuming the string "False" is falsy
if "False": # this is TRUE - it's a non-empty string!
print("runs")✅ Only the empty string "" is falsy. Compare values explicitly (flag == "False") or convert properly.
❌ Using 'or' for defaults when 0 is valid
qty = 0
result = qty or 1 # gives 1, but 0 was a real value!✅ 0 is falsy, so or discards it. When zero/empty is legitimate, test is None instead: qty if qty is not None else 1.
❌ Forgetting all([]) is True
items = []
if all(x > 0 for x in items):
print("all positive") # this RUNS on empty input✅ all() of an empty iterable is True. Guard with if items and all(...) when emptiness should fail.
🎯 Mini Challenge: Form Validator
Build a tiny validator that uses truthiness, all(), and an or default.
# Mini Challenge: validate a signup form
def validate(form):
required = [form.get("name"), form.get("email"), form.get("pw")]
is_valid = all(required) # every field non-empty?
display = form.get("name") or "New User"
status = "OK" if is_valid else "MISSING FIELDS"
return display, status
print(validate({"name": "Ada", "email": "a@x.com", "pw": "secret"}))
print(validate({"name": "", "email": "b@x.com", "pw": "pw"}))
# Expected output:
# ('Ada', 'OK')
# ('New User', 'MISSING FIELDS')📚 Keep Learning
Go deeper with the official Python documentation:
- Truth Value Testing — the canonical list of falsy values and the rules.
- Boolean Operations — and, or, not — exactly what each operator returns and when it short-circuits.
- Built-in Functions — all() & any() — the reference for both aggregate truthiness helpers.
Frequently Asked Questions
Lesson complete — truthiness demystified!
You know the falsy values cold, you can test collections directly with if items:, you understand that and/or return operands and short-circuit, and you can validate with any() and all().
Practice quiz
Which of these is a FALSY value in Python?
- The string '0'
- The list [0]
- An empty list []
- The string 'False'
Answer: An empty list []. An empty list [] is falsy. The string '0', the list [0], and the string 'False' are all non-empty, so they are truthy.
What does bool('0') return?
- False
- True
- 0
- None
Answer: True. '0' is a non-empty string, so it is truthy — bool('0') is True. Only the empty string '' is falsy.
What does the expression 0 or 'fallback' evaluate to?
- True
- 0
- 'fallback'
- False
Answer: 'fallback'. or returns the first truthy operand; 0 is falsy, so it returns 'fallback'. This is the common default-value pattern.
What does 'a' and 'b' evaluate to?
- True
- 'a'
- 'b'
- False
Answer: 'b'. and returns the first falsy operand, or the last one if all are truthy. Both are truthy, so it returns the last: 'b'.
What does 0 and 'b' evaluate to?
- 0
- 'b'
- True
- False
Answer: 0. and short-circuits at the first falsy operand and returns it. 0 is falsy, so it returns 0 without evaluating 'b'.
What is the result of any([]) on an empty list?
- True
- False
- None
- It raises an error
Answer: False. any([]) is False — with no items, nothing is truthy, so any() returns False.
What is the result of all([]) on an empty list?
- True
- False
- None
- It raises an error
Answer: True. all([]) is True — with no items, nothing breaks the rule, so all() vacuously returns True.
Why can 'qty or 1' be a bug when qty is 0?
- 0 raises a TypeError
- 0 is falsy, so or discards it and returns 1 even though 0 was a real value
- or only works on strings
- It always returns True
Answer: 0 is falsy, so or discards it and returns 1 even though 0 was a real value. 0 is falsy, so 'qty or 1' gives 1 even when 0 is a legitimate value. Use 'qty if qty is not None else 1' instead.
What is the Pythonic way to check that a list 'cart' is non-empty?
- if len(cart) > 0:
- if cart != []:
- if cart:
- if bool(cart) == True:
Answer: if cart:. Because empty collections are falsy, 'if cart:' is the idiomatic, readable test for a non-empty collection.
What does 1 and 2 and 3 evaluate to?
- 1
- True
- 3
- 6
Answer: 3. When every operand is truthy, and returns the LAST one, so 1 and 2 and 3 evaluates to 3.
Continue this course
- Previous: Slicing Lists & Strings
- Next: None & NoneType — Use None correctly — is None vs ==, and the mutable-default-arg trap
- Quick reference: Python cheat sheet › Useful Builtins
Frequently asked questions
What exactly is 'truthiness' in Python?
Truthiness is the idea that every object has an inherent boolean value, even if it isn't a True or False. When you put any object in an if or while, Python asks 'is this truthy?' Empty collections, the number zero, empty strings, and None are falsy; almost everything else is truthy. This lets you write 'if items:' instead of 'if len(items) > 0:'.
Which values are falsy?
The standard falsy values are: False, None, zero of any numeric type (0, 0.0, 0j), and every empty container — empty string '', empty list [], empty tuple (), empty dict {}, and empty set. Everything else is truthy, including the string 'False', the string '0', and the list [0]. If it isn't on the falsy list, it's truthy.
Why do 'and' and 'or' sometimes return a value instead of True/False?
Because Python's and/or return one of the original operands, not a boolean. 'a or b' returns a if a is truthy, otherwise b — so 'name or "Guest"' gives a default. 'a and b' returns a if a is falsy, otherwise b. They also short-circuit: the second operand is only evaluated if needed, which lets you guard against errors.
When should I use any() and all()?
Use any(iterable) to ask 'is at least one item truthy?' and all(iterable) to ask 'are they ALL truthy?'. They short-circuit (any stops at the first truthy, all stops at the first falsy) and pair perfectly with a generator expression, like all(x > 0 for x in nums). Note any([]) is False and all([]) is True — the empty-case edge that trips people up.