When an expression mixes several operators, Python needs a consistent rule for deciding which one runs first. That rule is called operator precedence, and it's the same idea you learned in school as "order of operations" (PEMDAS) — except Python's full table has far more operators than just arithmetic, including comparisons, boolean logic, and bitwise operators.

Getting this wrong is a classic source of subtle bugs: the code runs without crashing, but computes the wrong answer because an operator fired in an order you didn't expect. Understanding precedence — and knowing when to just add parentheses instead of relying on memory — will save you from that entire class of mistake.

A Simplified Precedence Table

From highest precedence (evaluated first) to lowest (evaluated last), the operators you'll use most often rank roughly like this:

1. ()                  Parentheses (always evaluated first)
2. **                   Exponentiation
3. +x, -x, ~x           Unary plus, minus, bitwise NOT
4. *, /, //, %          Multiplication, division, floor division, modulus
5. +, -                 Addition, subtraction
6. <<, >>               Bitwise shifts
7. &                    Bitwise AND
8. ^                    Bitwise XOR
9. |                    Bitwise OR
10. ==, !=, <, >, <=, >=   Comparisons
11. not                 Boolean NOT
12. and                 Boolean AND
13. or                  Boolean OR

Operators higher in this list bind more tightly — they "grab" their operands before operators lower down get a chance. You don't need to memorize all 13 levels; most real bugs come from mixing arithmetic with comparisons, or comparisons with and/or.

Example: Arithmetic Before Comparison

result = 2 + 3 * 4
print(result)          # multiplication happens before addition

is_valid = 5 + 2 == 7
print(is_valid)        # addition happens before ==

Output:

14
True

In the second line, 5 + 2 is computed first (giving 7), and only then is it compared to 7 with ==. If comparisons ran before arithmetic, this would behave very differently — which is exactly the kind of assumption that trips people up when precedence isn't obvious at a glance.

A Tricky Example: and / or Mixed with Comparisons

age = 25
has_ticket = False

# Without parentheses — relies on precedence rules
can_enter = age >= 18 and has_ticket or age >= 65
print(can_enter)

# With parentheses — the intent is explicit, and identical here
can_enter_explicit = (age >= 18 and has_ticket) or (age >= 65)
print(can_enter_explicit)

Output:

False
False

Both lines give the same result, because and binds tighter than or — Python evaluates age >= 18 and has_ticket as one unit, then ors that with age >= 65. The two lines are logically identical, but the second one is far easier for a human reader to verify at a glance without recalling the precedence table.

Associativity: Left-to-Right vs Right-to-Left

When operators have the same precedence, associativity decides the order. Most operators are left-associative (evaluated left to right), but exponentiation ** is right-associative:

print(10 - 3 - 2)   # left-associative: (10 - 3) - 2
print(2 ** 3 ** 2)  # right-associative: 2 ** (3 ** 2), NOT (2 ** 3) ** 2

Output:

5
512

If ** were left-associative, 2 ** 3 ** 2 would be (2 ** 3) ** 2 = 64. Because it's right-associative, Python instead computes 3 ** 2 first, giving 2 ** 9 = 512 — a genuinely surprising result if you haven't seen this rule before.

The Practical Rule: When in Doubt, Add Parentheses

You don't need to have the whole table memorized to write correct code — you just need to recognize when an expression is ambiguous enough that a future reader (including you, in six months) might misread it. In those cases, wrap the part you mean to group in parentheses. It costs nothing at runtime and removes the guesswork entirely, which matters a lot once your conditions start combining comparisons with truthy and falsy values inside an if statement.