bool is a subclass of int
The gotcha
True and False are real ints. isinstance(True, int) is True. They participate in arithmetic, indexing, and dict-key comparisons in ways that surprise.
Minimal repro
True + True # 2
True * 5 # 5
sum([True, False, True]) # 2
[10, 20, 30][True] # 20 (used as index 1)
isinstance(True, int) # True
issubclass(bool, int) # True
{1: "a", True: "b"} # {1: 'b'} ← True == 1 and hash(True) == hash(1)
Why it happens
bool was added in Python 2.3 by subclassing int for backward compatibility — code that did if flag == 1: had to keep working. So True is literally 1 and False is 0, with overridden __repr__.
Two equal hashable values that compare equal collapse in dict/set keys. 1 == True == 1.0 all hash the same and behave as one key.
How to avoid
If you specifically need int and not bool, narrow the type:
def add(a: int, b: int) -> int:
if isinstance(a, bool) or isinstance(b, bool):
raise TypeError("bools not allowed")
return a + b
Or check type(x) is int rather than isinstance(x, int) — strict identity.
In dicts where keys are heterogeneous, never mix bool and int keys.
Interview angle
“What does sum([True, False, True]) evaluate to?” “What’s {1: 'a', True: 'b', 1.0: 'c'}?” (Answer: {1: 'c'} — all collapse, last write wins.)