
Python operator precedence is one of those topics that looks simple on the surface but quietly causes bugs in code that seems correct at first glance. When you write an expression like 3 + 4 * 2, Python does not just read it left to right — it applies rules that determine which operations happen first. Understanding python operator precedence lets you write expressions that do exactly what you intend, without relying on guesswork or excessive parentheses.
This guide walks through every level of Python's precedence hierarchy, explains the associativity rules that govern how same-precedence operators are grouped, and shows practical examples of what happens when precedence works in surprising ways.
Operator precedence in Python refers to the set of rules that determine which operator gets evaluated first when an expression contains multiple operators. Python evaluates higher-precedence operators before lower-precedence ones, regardless of their position in the expression.
You may already be familiar with this from basic math — multiplication happens before addition. Python follows the same principle, but extends it to cover dozens of operators: arithmetic, comparison, logical, bitwise, and more.
Here is a simple example that shows python operator precedence at work:
result = 2 + 3 * 4
print(result)
Output
14
Even though the + appears first in the expression, Python evaluates 3 * 4 first because multiplication has higher precedence than addition. The result is 2 + 12, which gives 14, not 20.
Python defines a clear hierarchy for its operators. The table below lists operator groups from highest precedence (evaluated first) to lowest precedence (evaluated last):
| Precedence | Operator | Description |
|---|---|---|
| 1 (highest) | () | Parentheses |
| 2 | ** | Exponentiation |
| 3 | +x, -x, ~x | Unary plus, unary minus, bitwise NOT |
| 4 | *, /, //, % | Multiplication, division, floor division, modulo |
| 5 | +, - | Addition, subtraction |
| 6 | <<, >> | Bitwise shift operators |
| 7 | & | Bitwise AND |
| 8 | ^ | Bitwise XOR |
| 9 | | | Bitwise OR |
| 10 | ==, !=, >, <, >=, <=, is, is not, in, not in | Comparisons, identity, membership |
| 11 | not | Logical NOT |
| 12 | and | Logical AND |
| 13 (lowest) | or | Logical OR |
This table is your reference point every time you write a complex expression. Python's official documentation maintains the full operator precedence table if you want to cross-reference it.
Arithmetic operators follow the familiar PEMDAS-style rules from mathematics. Exponentiation comes before multiplication and division, which come before addition and subtraction.
a = 2 + 3 ** 2
b = 10 - 4 / 2
c = 5 * 3 + 8 // 3
print(a)
print(b)
print(c)
Output
11
8.0
17
In the first expression, 3 ** 2 is evaluated first (giving 9), then 2 + 9 gives 11. In the second, 4 / 2 is evaluated first (giving 2.0), then 10 - 2.0 gives 8.0. In the third, 5 * 3 gives 15 and 8 // 3 gives 2, then 15 + 2 gives 17.
Exponentiation deserves special attention because it has the highest precedence among arithmetic operators:
import math
x = -2 ** 2
y = (-2) ** 2
print(x)
print(y)
Output
-4
4
This is a common source of confusion. In x = -2 ** 2, Python first applies the exponentiation 2 ** 2 = 4, then applies the unary minus to get -4. The - here is treated as a unary operator applied after the exponentiation. Adding parentheses as in (-2) ** 2 forces the minus to bind to 2 first, producing 4.
Comparison operators in Python all sit at the same precedence level. What makes them unique in Python is that they support chaining — you can write expressions like 1 < x < 10 and Python evaluates them correctly.
x = 5
result1 = 1 < x < 10
result2 = x > 3 and x < 8
result3 = 2 + 3 == 5
print(result1)
print(result2)
print(result3)
Output
True
True
True
In 1 < x < 10, Python evaluates it as (1 < x) and (x < 10). This chaining behavior is built into the language and is a clean, readable feature that many other languages do not support.
Notice that 2 + 3 == 5 works correctly because + has higher precedence than ==. Python computes 2 + 3 = 5 first, then compares 5 == 5.
Logical operators follow a clear order: not is evaluated before and, which is evaluated before or. This is critical to understand when writing conditions.
a = True
b = False
c = True
result1 = a or b and c
result2 = (a or b) and c
result3 = not a or b
print(result1)
print(result2)
print(result3)
Output
True
True
False
In a or b and c, Python evaluates b and c first (because and has higher precedence than or), giving False and True = False, then True or False = True.
In not a or b, Python evaluates not a first (unary not has highest logical precedence), giving not True = False, then False or False = False.
These differences can completely change your program's logic if you do not account for them.
Real-world Python code often mixes arithmetic, comparison, and logical operators in the same expression. Python's precedence rules handle this consistently, evaluating arithmetic first, then comparisons, then logical operators.
score = 75
passing = score >= 60 and score <= 100
age = 20
eligible = age >= 18 and age * 2 < 100
print(passing)
print(eligible)
Output
True
True
In score >= 60 and score <= 100, Python evaluates both comparison expressions first (score >= 60 is True, score <= 100 is True), then combines them with and.
In age * 2 < 100, Python evaluates age * 2 = 40 first, then 40 < 100 = True, then combines with age >= 18 using and.
Bitwise operators work on the binary representations of integers. Their precedence sits between arithmetic operators and comparison operators, with the following order from highest to lowest: ~ (NOT), then << and >> (shifts), then & (AND), then ^ (XOR), then | (OR).
a = 0b1100 # 12
b = 0b1010 # 10
result1 = a & b
result2 = a | b
result3 = a ^ b
result4 = a >> 1
print(bin(result1))
print(bin(result2))
print(bin(result3))
print(bin(result4))
Output
0b1000
0b1110
0b110
0b110
The & operation performs a bitwise AND on each bit position. The | performs a bitwise OR. The ^ performs XOR (exclusive OR). The >> right-shift moves all bits one position to the right, which is equivalent to integer division by 2.
When mixing bitwise and arithmetic operators, be aware that arithmetic has higher precedence than bitwise shifts, which have higher precedence than &, ^, and |:
x = 4 + 2 << 1
y = 4 + (2 << 1)
z = (4 + 2) << 1
print(x)
print(y)
print(z)
Output
12
8
12
In 4 + 2 << 1, Python evaluates 4 + 2 = 6 first (addition before shift), then 6 << 1 = 12. The parenthesized versions make the evaluation order explicit.
When two operators have the same precedence level, Python uses associativity rules to decide the evaluation order. Most operators in Python are left-associative, meaning expressions are evaluated left to right. The only right-associative operator is exponentiation (**).
Left-associativity example:
result = 20 - 5 - 3
print(result)
Output
12
Because - is left-associative, Python evaluates (20 - 5) - 3 = 15 - 3 = 12. If it were right-associative, it would compute 20 - (5 - 3) = 20 - 2 = 18, which is different.
Right-associativity with exponentiation:
result = 2 ** 3 ** 2
print(result)
Output
512
Because ** is right-associative, Python evaluates 3 ** 2 = 9 first, then 2 ** 9 = 512. If it were left-associative, it would compute (2 ** 3) ** 2 = 8 ** 2 = 64. The right-to-left rule for exponentiation follows standard mathematical convention.
Parentheses always have the highest precedence in Python. Wrapping any part of an expression in parentheses forces it to be evaluated first, regardless of the operators inside. This is the most reliable way to ensure your expressions evaluate exactly as intended.
a = (2 + 3) * 4
b = 2 + 3 * 4
c = (10 - 2) ** (1 + 1)
d = not (True or False)
print(a)
print(b)
print(c)
print(d)
Output
20
14
64
False
Using parentheses is also good practice for readability, even when they are not strictly required. If an expression is complex enough that a reader might be unsure of the evaluation order, adding parentheses clarifies your intent without changing functionality.
Python 3.8 introduced the walrus operator :=, which assigns a value and returns it within an expression. It has very low precedence — lower than most operators, but higher than the comma.
import re
data = "Score: 95"
if match := re.search(r'\d+', data):
value = int(match.group())
doubled = value * 2
print(doubled)
Output
190
The walrus operator allows the assignment and the condition check to happen together. Because := has low precedence, the right-hand expression is fully evaluated before the assignment occurs. You can read more about its behavior in the walrus operator documentation.
Understanding where mistakes commonly occur helps you avoid them in your own code.
Mistake 1 — Confusing not with low arithmetic precedence:
x = 5
wrong = not x == 5
correct = (not x) == 5
print(wrong)
print(correct)
Output
False
False
In not x == 5, comparison x == 5 is evaluated first (comparison beats not), giving not True = False. In (not x) == 5, not x gives not 5 = False (since 5 is truthy), then False == 5 = False. Both return False here, but for different reasons — and with different values of x, they diverge.
Mistake 2 — Assuming or and and have equal precedence:
flag = False or True and False
print(flag)
Output
False
Because and binds tighter than or, Python evaluates True and False = False first, then False or False = False. If both had equal precedence and evaluated left-to-right, False or True would give True, then True and False would give False — the same result here, but different in other cases.
This example pulls together arithmetic, comparison, logical, and bitwise operators in a real calculation, demonstrating how python operator precedence controls the flow from start to finish.
def evaluate_expression_demo():
# Arithmetic with exponentiation and floor division
base = 2 ** 4 + 10 // 3
print(f"2 ** 4 + 10 // 3 = {base}")
# Unary minus and exponentiation order
neg_exp = -3 ** 2
neg_exp_paren = (-3) ** 2
print(f"-3 ** 2 = {neg_exp}")
print(f"(-3) ** 2 = {neg_exp_paren}")
# Mixed arithmetic and comparison
score = 82
grade_a = score >= 90
grade_b = score >= 80 and score < 90
print(f"Grade A: {grade_a}")
print(f"Grade B: {grade_b}")
# Logical precedence: and before or
is_weekend = False
is_holiday = True
has_task = True
day_off = is_weekend or is_holiday and not has_task
print(f"Day off: {day_off}")
# Bitwise operators
flags = 0b1010
mask = 0b1100
result = flags & mask | (flags ^ mask) >> 1
print(f"Bitwise result: {bin(result)}")
# Associativity: right-associative exponentiation
tower = 2 ** 3 ** 2
print(f"2 ** 3 ** 2 (right-assoc): {tower}")
# Parentheses forcing evaluation order
forced = (2 + 3) * (4 - 1) ** 2
natural = 2 + 3 * 4 - 1 ** 2
print(f"(2 + 3) * (4 - 1) ** 2 = {forced}")
print(f"2 + 3 * 4 - 1 ** 2 = {natural}")
evaluate_expression_demo()
Output
2 ** 4 + 10 // 3 = 19
-3 ** 2 = -9
(-3) ** 2 = 9
Grade A: False
Grade B: True
Day off: False
Bitwise result: 0b1011
2 ** 3 ** 2 (right-assoc): 512
(2 + 3) * (4 - 1) ** 2 = 45
2 + 3 * 4 - 1 ** 2 = 13
This example demonstrates every major precedence rule: exponentiation before addition, unary minus applied after exponentiation, arithmetic evaluated before comparison, and evaluated before or, not before and, right-associativity of **, and parentheses overriding everything. Refer back to the Python language reference for the authoritative precedence table whenever you write complex expressions.