Boolean Values
True and False are the only two bool values in Python, but nearly every object can stand in for one through truth-value testing — the mechanism behind every if, while, and implicit boolean context.
Python's bool type has exactly two instances: True and False. But Python doesn't require an explicit bool in conditions — any object can be tested for truthiness, following well-defined rules for what counts as truthy and what counts as falsy. This topic covers the bool type itself, the truth-value-testing protocol, and how bool() and None fit into the picture.
True and False
True and False are the two singleton instances of the bool type, which — as covered in Built-in Data Types — is a subclass of int. This means True and False behave as 1 and 0 in arithmetic contexts, while still printing and comparing as booleans in normal use.
print(type(True)) # <class 'bool'>
print(True == 1) # True
print(False == 0) # True
print(True + True) # 2 -- arithmetic works because bool IS-A intTruth Value Testing
Any object can be used where a boolean is expected — in an if, while, and/or, or a call to bool(). Python evaluates the object's truthiness by calling its __bool__ method if defined, or falling back to __len__ (an object with __len__ is falsy if its length is 0, truthy otherwise). Objects that define neither are considered truthy by default.
class Cart:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
empty_cart = Cart([])
full_cart = Cart(["apple"])
print(bool(empty_cart)) # False -- len() is 0
print(bool(full_cart)) # True -- len() is nonzero
if empty_cart:
print("has items")
else:
print("cart is empty") # this branch runsThe Falsy Values
Python defines a specific, memorizable set of built-in values that are falsy. Everything else is truthy.
Falsy values:
False
None
0 (int zero)
0.0 (float zero)
0j (complex zero)
"" (empty string)
[] (empty list)
() (empty tuple)
{} (empty dict)
set() (empty set)
Any object whose __bool__ returns False,
or whose __len__ returns 0 (and no __bool__ is defined)for value in (False, None, 0, 0.0, 0j, "", [], (), {}, set()):
print(repr(value), bool(value))bool()
bool(x) explicitly converts any object to its truthiness as a bool. It's the same evaluation Python performs implicitly in an if or while, made explicit and returning an actual True/False value you can store or pass around.
print(bool("hello")) # True -- non-empty string
print(bool("")) # False -- empty string
print(bool(42)) # True -- nonzero
print(bool(0)) # False -- zero
print(bool([1, 2])) # True -- non-empty list
print(bool(None)) # FalseNone and Boolean Context
None is always falsy, but it's important to distinguish "falsy" from "is None." A variable that is 0, "", or [] is also falsy but is not None — conflating these can hide bugs when you specifically need to detect "no value was provided" versus "an empty/zero value was provided."
Use if x is None: when you specifically mean "no value was given"; use if not x: (or if x:) when you mean "falsy/empty in the general sense." They are not interchangeable.
def process(data=None):
if data is None: # specifically checks for 'not provided'
data = []
data.append("processed")
return data
print(process()) # ['processed'] -- None became a fresh list
print(process([])) # ['processed'] -- an explicitly empty list still works correctly
# Contrast with the buggy version:
def process_buggy(data=None):
if not data: # WRONG if the caller intentionally passes an empty list/0/""
data = []
...Truthy/Falsy Objects: Custom Classes
Any user-defined class can control its own truthiness by implementing __bool__. This is useful for domain objects that have a natural notion of "empty" or "zero" beyond simple length.
class Balance:
def __init__(self, amount):
self.amount = amount
def __bool__(self):
return self.amount != 0
zero_balance = Balance(0)
positive_balance = Balance(50)
print(bool(zero_balance), bool(positive_balance)) # False True
if positive_balance:
print("account has funds")Practical Usage in Conditions
Relying on truthiness rather than explicit comparisons is idiomatic Python ("Pythonic") for common emptiness/zero checks, but should be used deliberately — not as a substitute for a clear is None check when None specifically matters.
names = []
if names: # Pythonic: True only if the list is non-empty
print(names[0])
else:
print("no names yet")
count = 0
if count: # False when count is 0
print("has items")
else:
print("count is zero")Key Takeaways
bool has exactly two instances, True and False, and is a subclass of int (True == 1, False == 0).
Truth value testing lets any object be used in a boolean context; Python calls __bool__ if defined, else falls back to __len__ == 0, else treats the object as truthy.
The full set of built-in falsy values is: False, None, 0, 0.0, 0j, "", [], (), {}, and set().
bool(x) makes truthiness evaluation explicit and returns an actual True/False.
None is always falsy, but "is falsy" and "is None" are different checks — use is None when you specifically need to detect absence of a value.
def set_count(count=None): if not count: # also true for count == 0, which may be a valid input! count = 10 return count print(set_count(0)) # 10 -- probably not what was intended def set_count(count=None): if count is None: # only true when count truly wasn't provided count = 10 return count print(set_count(0)) # 0 -- correctly preserves an explicit zero
not count treats 0, empty containers, and None identically. When zero or empty is a meaningfully different case from 'not provided', check is None explicitly.
if is_valid == True: ...
if is_valid: ...
Comparing a boolean to True/False explicitly is redundant and non-idiomatic; the value's own truthiness already expresses the check directly.
What are the two instances of bool, and what type is bool a subclass of?
True and False; bool is a subclass of int.
List all built-in falsy values.
False, None, 0, 0.0, 0j, "", [], (), {}, and set().
How does Python determine the truthiness of a custom object with no __bool__ but a __len__ method?
It falls back to __len__: the object is falsy if len(obj) == 0, truthy otherwise.
Why is if x is None different from if not x?
is None only matches the specific None singleton; not x matches None as well as any other falsy value (0, "", [], etc.), which may incorrectly conflate 'not provided' with 'empty/zero'.
What does bool("False") evaluate to, and why might that surprise a beginner?
True -- the string "False" is a non-empty string, and any non-empty string is truthy regardless of its text content.
How can a user-defined class customize its own truthiness?
By implementing a __bool__ method that returns True or False based on the object's own logic.
Is 0.0 == False true in Python? Why?
Yes -- bool is a numeric subclass of int, and 0.0 numerically equals 0, which equals False under Python's numeric equality rules.
Write a function first_truthy(items) that returns the first truthy value in a list, or None if none exist.
def first_truthy(items): for item in items: if item: return item return None print(first_truthy([0, "", None, [], 5, "x"])) # 5
Iterate and return on the first item whose truthiness is True; if the loop completes without finding one, return None.
What does this code print?
[False, True, False, True, False, True, False, True] -- each value's truthiness is evaluated independently per the falsy-value rules.
Write a class Inventory with a __bool__ method that is truthy only when its stock count is greater than zero, and demonstrate it in an if statement.
class Inventory: def __init__(self, stock): self.stock = stock def __bool__(self): return self.stock > 0 empty = Inventory(0) stocked = Inventory(5) for inv in (empty, stocked): if inv: print("in stock") else: print("out of stock")
__bool__ is invoked automatically by the if statement; it returns True only when stock > 0, so empty prints 'out of stock' and stocked prints 'in stock'.
values = [0, 1, False, True, "", "a", [], [0]]
print([bool(v) for v in values])