Yes, Python uses a fixed operator-precedence table; parentheses override it, and equal-precedence operators group by associativity.
You’ve seen it: an expression looks “obvious,” you run it, and the result lands sideways. That moment isn’t Python being random. It’s Python being strict.
This article gives you a clean mental model for how Python decides what happens first, what binds together, and when left-to-right reading still matters. You’ll also get practical patterns you can copy into real code so you don’t end up sprinkling parentheses like confetti.
What People Mean By “Order Of Operations” In Python
When most people say “order of operations,” they’re mixing three related rules. Python treats them as separate ideas, and that split clears up confusion fast.
- Precedence: which operators bind tighter in a single expression.
- Associativity: when two operators share precedence, how Python groups them.
- Evaluation order: the order Python runs the pieces that produce values.
Precedence and associativity decide the shape of the expression tree. Evaluation order decides which side effects happen first, like function calls that print, log, mutate, or raise errors.
Does Python Follow Order Of Operations? In Real Code, Not Guesswork
Python follows a published precedence table, and it doesn’t change from one project to the next. That table answers questions like “Does multiplication bind tighter than addition?” and “Where do and and or sit?”
Still, two things trip people up:
- Some operators group right-to-left even though most group left-to-right.
- “Bind tighter” is not the same as “runs first” when function calls and side effects are involved.
If you keep those two points in mind, Python’s behavior stays steady and predictable.
Precedence: The Binding Strength Rule
Precedence answers one question: “If I remove parentheses, what groups together?”
Try this:
print(2 + 3 * 4) # 14
print((2 + 3) * 4) # 20
The second line forces a different grouping. Parentheses beat the default binding every time.
Associativity: What Happens When Precedence Ties
If operators share the same precedence level, Python groups them using associativity. Many operators group left-to-right. One famous case goes the other way: exponentiation.
print(2 ** 3 ** 2) # 512
print((2 ** 3) ** 2) # 64
2 ** 3 ** 2 groups as 2 ** (3 ** 2). If you want the other result, you must write it with parentheses.
Evaluation Order: Which Parts Get Run First
Evaluation order matters when an expression contains function calls, index access, attribute access, or anything that can fail or change state. Python evaluates the pieces that supply operator operands in a left-to-right flow. That doesn’t override precedence. It just decides which operand value gets computed first.
Say you do this:
def left():
print("left ran")
return 10
def right():
print("right ran")
return 2
print(left() / right())
You’ll see “left ran” before “right ran,” then the division happens after both values exist. The operator’s precedence didn’t change; Python just computed the operand values in a stable order.
Operator Precedence In Python: A Practical Map
You don’t need to memorize the full list to write clean code. You do need a dependable way to check it, plus a handful of “sticky” tiers you’ll meet every day.
The official table lives in the language reference. When you want the source of truth, use it: Python operator precedence table.
Here’s a working map you can keep in your head, with notes that match real coding habits.
Quick Rules That Save You From Surprises
- Parentheses win. If you want a reader to stop guessing, add
(). **groups right-to-left.- Unary operators like
-xbind tighter than*and+. - Comparisons chain in Python (
1 < x < 10) and that chain is not the same as(1 < x) < 10. notbinds tighter thanand, which binds tighter thanor.
Next comes the detailed table so you can spot where an operator sits and what to do when the line starts to feel cramped.
| Tier (High → Low) | Operators You’ll See | What This Means In Practice |
|---|---|---|
| Grouping and calls | (), function calls, indexing, attribute access |
These form tight “units” like obj.method()[0] before math kicks in. |
| Exponent | ** |
Groups right-to-left: a ** b ** c becomes a ** (b ** c). |
| Unary | +x, -x, ~x |
-x**2 means -(x**2), not (-x)**2. |
| Multiply tier | *, /, //, %, @ |
These bind tighter than + and -. |
| Add tier | +, - |
Runs after the multiply tier once operands are computed. |
| Shifts | <<, >> |
Often clearer with parentheses in mixed math, since readers don’t expect shifts mid-formula. |
| Bitwise | &, ^, | |
These sit below shifts. Parentheses help when mixing with comparisons. |
| Comparisons | <, <=, >, >=, ==, !=, in, is |
Comparisons chain. A chain reads cleanly when used for range checks. |
| Boolean | not, and, or |
not binds tightest. Add parentheses when mixing and and or. |
| Conditional | x if cond else y |
Readable with parentheses when nested inside a larger expression. |
| Lambda | lambda |
Lowest. Wrap in parentheses when passing lambdas around. |
Where Python’s Rules Trip People Up
Most “Python ignored order of operations” stories come from a few repeat offenders. Once you know them, you’ll spot them while typing.
Unary Minus With Exponentiation
This one catches even seasoned coders:
print(-3 ** 2) # -9
print((-3) ** 2) # 9
Python groups exponentiation before unary minus, so -3 ** 2 means -(3 ** 2). If you’re working with formulas, write the parentheses you mean.
Chained Comparisons Aren’t Two Separate Booleans
Python allows chained comparisons, and it evaluates them as a chain with shared middle terms. That can be clean and tight when you use it on purpose:
0 <= x < 10
The middle value x gets evaluated once for the chain. That’s one reason the chain reads well for range checks.
and / or Mixing Without Parentheses
Python binds and tighter than or. That means this:
flag = a or b and c
groups as:
flag = a or (b and c)
If your intent is (a or b) and c, write it. Boolean logic is a place where extra parentheses pay rent by making intent visible.
Floor Division And Modulo With Negatives
// and % sit in the multiply tier, so they bind before addition. The surprise comes from how they behave with negative numbers, not from precedence.
print(-7 // 3) # -3
print(-7 % 3) # 2
If you’re doing indexing math, time buckets, or wraparound logic, test negative inputs early so you don’t ship a quiet edge-case bug.
When Parentheses Beat Precedence
Python’s rules are consistent. Readers aren’t. If an expression makes a teammate slow down and re-parse, you can choose clarity over cleverness.
A simple habit works well: add parentheses at “meaning boundaries.” If you can name a chunk in plain words, it can be wrapped.
Clarity Patterns You Can Reuse
- Wrap boolean groups:
(is_admin or is_owner) and has_token - Wrap bitwise intent:
(mask & flags) != 0 - Wrap mixed arithmetic:
(subtotal - discount) * tax_rate - Wrap shifts in math:
value + (shifted << 2)
None of these parentheses change Python’s correctness. They change human speed.
Common Patterns And How Python Groups Them
The table below shows expressions you’ll see in day-to-day Python, the grouping Python applies, and when adding parentheses makes the line easier to scan.
| Expression | Groups As | When To Add Parentheses |
|---|---|---|
a + b * c |
a + (b * c) |
When a is also a compound term, wrap both sides for symmetry. |
-x ** 2 |
-(x ** 2) |
When you mean squaring a negative: write (-x) ** 2. |
a or b and c |
a or (b and c) |
When the left side is meant to be paired with b. |
mask & flags == 0 |
mask & (flags == 0) (not what you want) |
Write (mask & flags) == 0 to match intent. |
a < b <= c |
Chained comparison | Keep as-is when it reads as a range check. |
x if ok else y + z |
x if ok else (y + z) |
Wrap the else side when it’s more than a single token. |
n // 10 % 10 |
(n // 10) % 10 |
Add parentheses when teaching or when the expression sits inside a bigger line. |
A Simple Way To Reason About Any Expression
If you’re unsure what Python will do, don’t guess. Use a repeatable checklist. It’s fast, and it stops “I thought it meant…” bugs.
- Mark parentheses first. Anything inside
()is a unit. - Locate the lowest-precedence operator at the top level. That often becomes the “last split” in the expression tree.
- Check ties with associativity. Watch for
**grouping right-to-left. - Scan for side effects. Function calls, indexing, and attribute access run while producing operands.
- Decide on readability. If a human needs extra time, add parentheses that match your intent.
Want the official wording behind precedence and expression behavior? The reference section on expressions is the anchor: Python expressions reference.
Practical Tips For Writing Expressions That Don’t Bite Back
Clean code isn’t about showing you know the precedence table. It’s about making the next reader fast and confident.
Prefer Named Intermediate Values For Dense Math
If a line has three operator tiers plus a conditional, it’s begging for names:
net = subtotal - discount
tax = net * tax_rate
total = net + tax
You get debuggable checkpoints, and you can log each part without rewriting the line.
Use Parentheses Around Boolean Intent
Boolean expressions tend to grow. Start clean:
allowed = (is_admin or is_owner) and has_token and not is_suspended
That reads as three gates. The grouping is visible without a reader running the precedence ladder in their head.
Avoid Clever Bitwise Mixes In One Line
Bitwise operators have their own precedence tiers, and most readers don’t keep them memorized. Parentheses are cheap:
enabled = ((mask & flags) != 0) and (mode < 3)
Sanity-Check With A Tiny REPL Probe
When you’re unsure, run a one-liner in a REPL or a test. The fastest fix is often: “Run it once, then wrap what you meant.”
Takeaway: Python Is Consistent, So Your Code Can Be Too
Python does follow an order of operations: a fixed precedence table, steady associativity rules, and a predictable operand evaluation flow. Most surprises come from mixing these ideas or trusting a reader to infer your intent.
If an expression is doing real work, give it guardrails. Parentheses, intermediate names, and small tests make the behavior plain. That’s the kind of code you can ship and revisit later without squinting.
References & Sources
- Python Software Foundation.“Operator precedence.”Official precedence table showing how Python groups operators.
- Python Software Foundation.“Expressions.”Language reference for expression structure and evaluation behavior.
