max(a, b) is 2–7x slower than a plain comparison
Python trivia that surprised a colleague this week: max(a, b) is 2–7x slower than a plain comparison.
I measured across four interpreters (timeit, best of 5×2M iterations, ns/op):
| Python | if/else | max() | Slowdown |
|---|---|---|---|
| 3.9 | 14 ns | 50 ns | 3.6x |
| 3.10 | 16 ns | 46 ns | 2.9x |
| 3.12 | 8 ns | 60 ns | 7.5x! |
| 3.14 | 10 ns | 20 ns | 2x |
Why?
The comparison compiles down to a couple of bytecode instructions. max() is a function call: Python looks up the name in globals (someone might have shadowed it!), builds the call, and goes through the generic iterate-over-arguments machinery max doesn't know it's getting exactly two ints. All of that costs more than the comparison itself.
Two things this table shows beyond the trivia
It's not monotonic across versions. max() got slower in 3.12 (60 ns) and then 3x faster in 3.14 (20 ns). Micro-performance shifts between releases which is exactly why you measure instead of memorizing rules. (I saw the same effect leading a Python 3.12 migration at work: some hot paths changed speed before we touched a line.)
Does it matter in real code? Almost never. 10–40 nanoseconds is not your bottleneck. Write max() when it's clearer, and it usually is. But in a genuinely hot loop, millions of iterations, math-heavy code, swapping it for a comparison is free performance.
Rule I follow: readability by default, bytecode awareness when the profiler says so.
Comments