Operator Precedence
When an expression mixes several operators — 2 + 3 * 4 — Python has
to decide which operation happens first. That decision is governed by
operator precedence: a fixed ranking of which operators "bind
tighter" than others. Operators with higher precedence are evaluated
before operators with lower precedence, regardless of the order they
appear in the line. Get the ranking wrong in your head, and you get a
number that looks plausible but is silently incorrect — one of the
most common sources of subtle bugs in otherwise working code.
The full precedence table
The table below lists Python's operators from highest precedence (evaluated first) to lowest (evaluated last). Operators on the same row share equal precedence and are then resolved by associativity — the order in which same-precedence operators are applied when several appear side by side.
Precedence | Operator(s) | Description | Associativity |
|---|---|---|---|
1 (highest) |
| Parentheses — grouping, forces evaluation order | n/a |
2 |
| Exponentiation | Right-to-left |
3 |
| Unary plus, unary minus, bitwise NOT | Right-to-left |
4 |
| Multiplication, division, floor division, modulo | Left-to-right |
5 |
| Addition, subtraction | Left-to-right |
6 |
| Bitwise left shift, right shift | Left-to-right |
7 |
| Bitwise AND | Left-to-right |
8 |
| Bitwise XOR | Left-to-right |
9 |
| Bitwise OR | Left-to-right |
10 |
| Comparisons, identity, and membership tests | Left-to-right (chained) |
11 |
| Boolean negation | Right-to-left |
12 |
| Boolean AND | Left-to-right |
13 (lowest) |
| Boolean OR | Left-to-right |
Why exponentiation is right-associative
Most binary operators in Python are left-associative: when the same
operator appears twice in a row, evaluation proceeds left to right.
** is the notable exception — it is right-associative, which
matches how exponent towers are conventionally read in mathematics.
** chains right-to-left
print(2 ** 3 ** 2) # Evaluated as 2 ** (3 ** 2) = 2 ** 9 = 512 # NOT (2 ** 3) ** 2 = 8 ** 2 = 64 print(-2 ** 2) # Unary minus has LOWER precedence than **, so this is -(2 ** 2) = -4 # NOT (-2) ** 2 = 4
Walking through a mixed expression step by step
Here is a single expression that touches five different precedence
levels at once. Rather than evaluating left to right, Python resolves
it strictly by precedence: exponentiation first, then the
multiplicative operators (*, //, %) left to right, then the
additive operators (+, -) left to right.
A mixed expression
result = 2 + 3 * 4 ** 2 // 5 - 1 print(result)
10
Step by step, following the precedence table:
4 ** 2— exponentiation runs first (highest precedence among the operators present):4 ** 2 = 16. The expression is now2 + 3 * 16 // 5 - 1.3 * 16— multiplication is next, evaluated left to right among the multiplicative operators:3 * 16 = 48. Now2 + 48 // 5 - 1.48 // 5— floor division shares precedence with*, and since it appears next moving left to right, it runs now:48 // 5 = 9(floor division truncates toward negative infinity, and 48 / 5 = 9.6, so the result is 9). Now2 + 9 - 1.2 + 9— addition and subtraction share the lowest precedence of the operators involved and are evaluated left to right:2 + 9 = 11. Now11 - 1.11 - 1— final subtraction:11 - 1 = 10.
The result is 10. Notice that at no point did evaluation simply proceed
left to right across the whole expression — the exponent and the
multiplicative operators cut in first even though they are not first in
reading order.
Comparisons and boolean operators sit at the bottom
Comparisons (==, <, in, is, and friends) all bind tighter
than not, and, and or. This is why you can write conditions
without extra parentheses and have them mean what they look like they
mean.
Comparisons resolve before boolean logic
x = 5 print(x > 2 and x < 10) # Equivalent to (x > 2) and (x < 10) -> True and True -> True print(not x == 5) # Equivalent to not (x == 5) -> not True -> False print(1 < 2 < 3) # Chained comparison: equivalent to (1 < 2) and (2 < 3) -> True
Bitwise operators are lower precedence than comparisons
A very common bug: bitwise &, |, and ^ bind more loosely than
comparisons, which is the opposite of what many people assume coming
from C-like intuition about "and means &". This means
a == 1 & b == 2 does not do what it looks like it does.
Bitwise vs comparison precedence trap
a, b = 1, 2 # Looks like it should check "a == 1 AND b == 2", but it doesn't: print(a == 1 & b == 2) # & binds tighter than ==, so this is actually a == (1 & b) == 2 # 1 & 2 is 0, so this becomes a == 0 == 2 -> False (chained comparison) # What you almost certainly meant: print((a == 1) & (b == 2)) # Explicit parentheses -> True & True -> True (or 1, depending on types)