Skip to main content

Python

The language quirks that bite in interviews - the places where Python's answer is correct, surprising, and not what the code was trying to say.

Truthiness

and / or return an operand, not a bool

and and or short-circuit and hand back one of the operands themselves. and returns the first falsy operand, otherwise the last one. or returns the first truthy operand, otherwise the last one.

[] and 0 # [] left side falsy, `0` never evaluated
0 and 1 # 0
1 and 2 # 2 no falsy operand, so the last one
[] or 0 # 0 no truthy operand, so the last one
0 or "hi" # 'hi'

This is what makes x = cache.get(k) or compute() work, and also what makes it silently wrong when 0 is a legitimate cached value.

& is bitwise, not logical

& operates on bits, not truthiness, and it only exists for types that implement it.

1 & False # 0 False is the integer 0, so 1 & 0 == 0
True & False # False bool & bool stays a bool
{1, 2} & {2, 3} # {2} sets implement it as intersection
[] & False # TypeError: unsupported operand type(s) for &: 'list' and 'bool'

Note the asymmetry: bool & bool returns a bool, but mixing in an int returns an int. Reserve & and | for integers, sets, and NumPy/pandas arrays where they do elementwise work; use and / or / not for logic.

Falsy values by type

CategoryFalsy
BooleanFalse
NullNone
Numbers0, 0.0, 0j, Decimal(0), Fraction(0, 1)
Sequences'', (), [], range(0)
Mappings and sets{}, set(), frozenset()

Everything else is truthy, including "0", "False", [0], and [[]] - a container holding a falsy thing is still a non-empty container.

For your own classes, truthiness comes from __bool__(); if that is missing, Python falls back to __len__() != 0; if neither exists, the object is always truthy.