Booleans in Python: True, False and How to Check Them

A boolean in Python is a value that is either True or False, and nothing else:

is_ready = True
is_done = False

type(is_ready)              # <class 'bool'>
isinstance(is_ready, bool)  # True

Both must be capitalised. Lowercase true is just an undefined name, so it raises a NameError.

The trap worth knowing before anything else: bool("False") is True, because any non-empty string is truthy.

Everything on this page was run on Python 3.12.5, NumPy 2.5.3.

What is a boolean in Python?

It is the type with exactly two values, and it is what every comparison returns:

is_ready = True
is_done = False

print(is_ready, type(is_ready))
print(is_done, type(is_done))

print()
# comparisons produce booleans
print("3 > 2        ->", 3 > 2)
print("'a' in 'cat' ->", "a" in "cat")
print("5 == 5.0     ->", 5 == 5.0)

print()
# they must be capitalised
try:
    value = true
except NameError as err:
    print("true (lowercase) ->", type(err).__name__ + ":", err)

Output:

True <class 'bool'>
False <class 'bool'>

3 > 2        -> True
'a' in 'cat' -> True
5 == 5.0     -> True

true (lowercase) -> NameError: name 'true' is not defined

3 > 2 does not return the number 1 or the string “yes”. It returns the boolean True, which is why you can assign a comparison straight to a variable.

Python is case sensitive here. True and False are keywords; true and false are not defined at all.

Truthy and falsy values in Python

Every Python object can be used in an if, not just booleans. bool() shows you which way each one goes:

# every object is either truthy or falsy
falsy = [0, 0.0, "", [], {}, (), set(), None, False]
truthy = ["0", "False", [0], 0.1, " ", [[]]]

print("FALSY:")
for value in falsy:
    print(f"  bool({value!r:<8}) = {bool(value)}")

print("\nTRUTHY (these surprise people):")
for value in truthy:
    print(f"  bool({value!r:<8}) = {bool(value)}")

Output:

FALSY:
  bool(0       ) = False
  bool(0.0     ) = False
  bool(''      ) = False
  bool([]      ) = False
  bool({}      ) = False
  bool(()      ) = False
  bool(set()   ) = False
  bool(None    ) = False
  bool(False   ) = False

TRUTHY (these surprise people):
  bool('0'     ) = True
  bool('False' ) = True
  bool([0]     ) = True
  bool(0.1     ) = True
  bool(' '     ) = True
  bool([[]]    ) = True
Command Prompt listing which Python values are falsy and which are truthy
Nine falsy values. Everything else, including "0", is truthy.
  • Falsy — 0, 0.0, "", [], {}, (), set(), None, False.
  • Truthy — everything else, including "0", "False", [0] and a single space.
  • A list containing only falsy items is still truthy, because the list itself is not empty.

This is why if my_list: is the idiomatic way to check for a non-empty list. It reads better than len(my_list) > 0 and does the same job. NumPy arrays are the exception, as checking an empty NumPy array explains.

Why is bool(“False”) True in Python?

This catches out anyone reading booleans from a config file, a form or an environment variable:

answer = "False"

print('bool("False") ->', bool(answer), "  <- the string is not empty, so it is True")
print('bool("0")     ->', bool("0"), "  <- same reason")
print('bool("")      ->', bool(""))

print()
# so this check is always wrong
if answer:
    print("naive check: treated as True")

print()
# convert properly instead
def to_bool(text):
    return text.strip().lower() in {"true", "1", "yes", "y", "on"}

for text in ["True", "false", "1", "0", "yes", "no"]:
    print(f"  to_bool({text!r:<8}) = {to_bool(text)}")

Output:

bool("False") -> True   <- the string is not empty, so it is True
bool("0")     -> True   <- same reason
bool("")      -> False

naive check: treated as True

  to_bool('True'  ) = True
  to_bool('false' ) = False
  to_bool('1'     ) = True
  to_bool('0'     ) = False
  to_bool('yes'   ) = True
  to_bool('no'    ) = False
Command Prompt showing that the Python string False converts to the boolean True
"False" and "0" are both non-empty strings, so both are truthy.

bool() on a string asks one question only: is it empty? The contents are never inspected.

Parse the text yourself, as the helper above does. There is a fuller treatment in converting a string to a boolean.

How to check if a variable is a boolean

isinstance is the direct answer, and it behaves as you would expect in this direction:

import numpy as np

values = [True, 1, 0, "True", np.bool_(True)]

print(f"{'value':<8} {'isinstance(x, bool)':>20} {'type(x) is bool':>18}")
for value in values:
    print(f"{str(value):<8} {isinstance(value, bool)!s:>20} {type(value) is bool!s:>18}")

print()
print("numpy has its own boolean type:", type(np.bool_(True)))
print("so isinstance(np.bool_(True), bool) is", isinstance(np.bool_(True), bool))

Output:

value     isinstance(x, bool)    type(x) is bool
True                     True               True
1                       False              False
0                       False              False
True                    False              False
True                    False              False

numpy has its own boolean type: <class 'numpy.bool'>
so isinstance(np.bool_(True), bool) is False
Command Prompt comparing isinstance and type checks for Python booleans including a NumPy boolean
1 is not a boolean, and neither is NumPy’s bool_.
CheckAcceptsNote
isinstance(x, bool)True, FalseThe usual answer
type(x) is boolTrue, FalseSame here, since bool cannot be subclassed
x in (True, False)Also 1 and 0Because True == 1

Avoid the third row. 1 in (True, False) is True, because equality rather than identity is used.

NumPy’s bool_ is a separate type and fails isinstance(x, bool). That mirrors the integer case in checking for an integer.

Why is a Python boolean also an integer?

This explains several behaviours that otherwise look like bugs:

# bool is a subclass of int, which explains a lot of odd behaviour
print("bool inherits from:", [cls.__name__ for cls in bool.__mro__])

print()
print("int(True)  :", int(True))
print("int(False) :", int(False))
print("True + True:", True + True)
print("sum([True, False, True]):", sum([True, False, True]), "  counting matches")

print()
print("isinstance(True, int) :", isinstance(True, int), "  <- True is also an integer")
print("True == 1             :", True == 1)
print("True is 1             :", True is 1, "  but not the same object")

Output:

C:\pyguides\runs\boolean\ex_subclass.py:13: SyntaxWarning: "is" with 'int' literal. Did you mean "=="?
  print("True is 1             :", True is 1, "  but not the same object")
bool inherits from: ['bool', 'int', 'object']

int(True)  : 1
int(False) : 0
True + True: 2
sum([True, False, True]): 2   counting matches

isinstance(True, int) : True   <- True is also an integer
True == 1             : True
True is 1             : False   but not the same object

True is 1 and False is 0, all the way down. That is why True + True is 2 and why sum() counts a list of booleans.

It is also why an integer check accepts a boolean. If that matters, add and not isinstance(x, bool) to the test.

Note the last line: True == 1 is True but True is 1 is False. They compare equal without being the same object.

Boolean operators: and, or and not

The three operators do more than combine booleans. They short-circuit, and they return operands:

print("and / or / not:")
print("  True and False ->", True and False)
print("  True or False  ->", True or False)
print("  not True       ->", not True)

print()
# they short-circuit: the right side is skipped when the answer is already known
def noisy():
    print("    (the right side ran)")
    return True

print("  False and noisy() ->", False and noisy())
print("  True or noisy()   ->", True or noisy())

print()
# and they return an OPERAND, not a boolean
print("  'a' and 'b'     ->", repr("a" and "b"))
print("  0 or 'fallback' ->", repr(0 or "fallback"))
print("  [] or None      ->", repr([] or None))

Output:

and / or / not:
  True and False -> False
  True or False  -> True
  not True       -> False

  False and noisy() -> False
  True or noisy()   -> True

  'a' and 'b'     -> 'b'
  0 or 'fallback' -> 'fallback'
  [] or None      -> None
Command Prompt showing Python and or short circuiting and returning an operand rather than a boolean
'a' and 'b' returns 'b', not True.

Short-circuiting means the right-hand side is skipped once the answer is decided. False and anything() never calls the function.

That is what makes if user and user.is_active: safe. If user is None, the attribute access never happens.

or returning an operand gives you the default-value idiom: name = supplied or "Anonymous". Be careful with it when 0 or an empty string is a legitimate value.

Counting with booleans

Because True is 1, booleans and sum() combine into a neat counting idiom:

scores = [45, 82, 91, 38, 67, 95]
passed = [s >= 50 for s in scores]

print("scores :", scores)
print("passed :", passed)

print()
# because True is 1, sum() counts them
print("how many passed:", sum(passed))
print("did any pass   :", any(passed))
print("did all pass   :", all(passed))

print()
print("percentage:", f"{sum(passed) / len(passed):.0%}")

Output:

scores : [45, 82, 91, 38, 67, 95]
passed : [False, True, True, False, True, True]

how many passed: 4
did any pass   : True
did all pass   : False

percentage: 67%

sum(passed) counts how many comparisons were true. No loop and no counter variable.

any() and all() answer the other two questions, and both short-circuit as soon as the result is certain.

Common boolean mistakes

SymptomCauseFix
NameError: trueLowercase keywordUse True
"False" treated as trueAny non-empty string is truthyParse the text
Integer check accepts Truebool subclasses intAdd not isinstance(x, bool)
1 in (True, False) is trueEquality, not identityUse isinstance(x, bool)
NumPy value fails a bool checknp.bool_ is a different typeCall bool(x) first
or default overrides 00 is falsyCompare with is None

Related Python type and conversion guides:

Frequently asked questions

What is a boolean in Python?

A value that is either True or False. It is the type every comparison returns, and it is documented in the Python boolean type reference.

How do I check if a variable is a boolean in Python?

isinstance(value, bool). Avoid value in (True, False), which also accepts 1 and 0.

Why is bool(“False”) True in Python?

bool() on a string only checks whether it is empty. "False" has five characters, so it is truthy.

What values are falsy in Python?

0, 0.0, "", [], {}, (), set(), None and False. Everything else is truthy.

Is a boolean an integer in Python?

Yes. bool is a subclass of int, so True is 1 and True + True is 2.

Why does ‘a’ and ‘b’ return ‘b’ instead of True?

and and or return one of their operands rather than a boolean. and returns the last value when everything is truthy.

Why does true give a NameError?

Python’s keywords are capitalised. Write True and False.