Booleans and Truthiness
Python bool - True and False, truthy and falsy values, short-circuit operators, and when to use is vs ==.
A Python bool is one of two values: True or False. Comparisons (==, <, in) and logical operators (and, or, not) produce booleans. Beyond the two bool literals, many other values behave as true or false in a boolean context - this is called "truthiness."
bool(x) converts any value to its boolean equivalent. The falsy values are: 0, 0.0, "", b"", [], (), {}, set(), and None. Every other value is truthy. You can rely on this in if conditions without calling bool() explicitly.
# All falsy
bool(0) # False
bool("") # False
bool([]) # False
bool({}) # False
bool(None) # False
# All truthy
bool(1) # True
bool("hello") # True
bool([0]) # True - a list with one item, even if the item is 0
bool(0.001) # Trueand and or do not necessarily return True or False - they return one of their operands. or returns the first truthy operand (or the last operand if all are falsy). and returns the first falsy operand (or the last operand if all are truthy). This short-circuit behaviour is useful for defaults, but it also creates a common footgun.
# or returns the first truthy value
0 or "fallback" # 'fallback'
"primary" or "fallback" # 'primary'
[] or [1, 2] # [1, 2]
# and returns the first falsy value
1 and 2 # 2 (all truthy, returns last)
0 and "unreachable" # 0 (0 is falsy, short-circuits)
# Footgun: silently uses the fallback when 0 or "" is a valid value
count = 0
display = count or "no items" # 'no items' -- wrong when count is a valid 0is checks identity - whether two names refer to the same object in memory. == checks value equality. For None, is is the canonical idiom and is faster. For True and False, use truthiness (if x:) rather than is True or is False - they are fragile if the value is a truthy non-bool.
x = None
x is None # True - canonical None check
x == None # True - works, but non-idiomatic
# is True / is False are footguns
result = 1 # truthy, but not the bool True
result == True # True
result is True # False - 1 and True are different objects
# Prefer plain truthiness checks
if result: # idiomatic - "do I have a value?"
pass
if result is not None: # idiomatic - "was something provided?"
passIn production
if my_list: treats empty containers as false - convenient for "do I have items?", but catastrophic when 0, "", or [] is a legitimate value (a counter starting at zero, an empty form field, a response body that is intentionally empty). Use if x is not None: when the distinction between "absent" and "falsy but present" matters. and/or return operands not booleans, so default = config_value or "fallback" silently uses the fallback for 0, "", and [].
Enjoyed this? Get more essays on software craft delivered to your inbox.
Subscribe free