Every operator Python has, how tightly each one binds, and the surprising corners — floor division with negatives, and/or returning operands, chained comparisons and bit tricks.
Precedence table (highest first)
| Level | Operators | Notes |
|---|---|---|
| 1 | (…) […] {…}, x[i], x(…), x.attr | Grouping, subscription, calls, attribute access |
| 2 | await x | Inside async def |
| 3 | ** | Power — right-associative; binds tighter than a unary minus on its left |
| 4 | +x -x ~x | Unary plus, minus, bitwise NOT |
| 5 | * @ / // % | Multiplicative (@ is matrix multiplication) |
| 6 | + - | Additive |
| 7 | << >> | Shifts |
| 8 | & | Bitwise AND |
| 9 | ^ | Bitwise XOR |
| 10 | | | Bitwise OR |
| 11 | in not in is is not < <= > >= != == | All comparisons share one level and chain |
| 12 | not x | Boolean NOT |
| 13 | and | Short-circuit AND |
| 14 | or | Short-circuit OR |
| 15 | x if c else y | Conditional expression |
| 16 | lambda | Anonymous function |
| 17 | := | Assignment expression (walrus) — lowest |
Arithmetic
print(7 / 2, 7 // 2, 7 % 2) # 3.5 3 1
print(-7 // 2, -7 % 2) # -4 1
print(7 // -2, 7 % -2) # -4 -1
print(divmod(-7, 2)) # (-4, 1)
print(7.5 // 2, 7.5 % 2) # 3.0 1.5
print(2 ** 3 ** 2, (2 ** 3) ** 2) # 512 64
print(-2 ** 2, (-2) ** 2) # -4 4
print(2 ** -1, 10 ** 20) # 0.5 100000000000000000000| Operator | Meaning | Watch out |
|---|---|---|
/ | True division | Always returns a float: 4 / 2 == 2.0 |
// | Floor division | Rounds toward −∞, not toward 0: -7 // 2 == -4 (C/Java give -3) |
% | Modulo | Result has the sign of the divisor: -7 % 2 == 1; always (a // b) * b + a % b == a |
** | Power | Right-associative; pow(a, b, m) does fast modular exponentiation |
divmod(a, b) | (a // b, a % b) at once | Handy for digit extraction and time conversions |
Comparisons chain
x = 5
print(1 < x < 10, 10 > x >= 5) # True True
print(1 < 2 == 2) # True ← means (1 < 2) and (2 == 2)
print((1 < 2) == 2) # False ← True == 2 is False
print(False == False in [False]) # True ← (False == False) and (False in [False])
print("apple" < "banana" < "cherry") # True ← strings compare lexicographically
print([1, 2] < [1, 3], (2, 0) > (1, 9)) # True Truea < b < c evaluates b only once and means a < b and b < c. Sequences compare element by element, which is why tuples make great multi-key sort keys.
and, or, not — short-circuit and return operands
print(0 or "default", "x" or "default") # default x
print(0 and 1 / 0, 3 and 4) # 0 4 ← 1 / 0 is never evaluated
print([] or None or 0) # 0 ← every operand falsy → the last one
print(not "", not "hi") # True False
name = ""
print(name or "Anonymous") # Anonymous| Expression | Returns |
|---|---|
a or b | a if a is truthy, otherwise b |
a and b | a if a is falsy, otherwise b |
not a | Always a real bool |
Bitwise operators & tricks
a, b = 0b1100, 0b1010 # 12, 10
print(a & b, a | b, a ^ b) # 8 14 6
print(bin(a & b), ~a) # 0b1000 -13 ← ~x == -x - 1
print(1 << 4, 100 >> 2) # 16 25 ← x << k == x * 2**kdef is_power_of_two(x):
return x > 0 and x & (x - 1) == 0 # clears the lowest set bit
print(is_power_of_two(64), is_power_of_two(96)) # True False
print(40 & -40) # 8 ← lowest set bit of 0b101000
print((13 >> 2) & 1) # 1 ← bit 2 of 0b1101
print((255).bit_count(), (255).bit_length()) # 8 8
READ, WRITE, EXEC = 1, 2, 4 # flags packed in one int
perms = READ | WRITE
perms &= ~WRITE # clear a flag
perms |= EXEC # set a flag
print(perms, bool(perms & READ), bool(perms & WRITE)) # 5 True False
nums = [4, 1, 2, 1, 2]
single = 0
for n in nums:
single ^= n # x ^ x == 0, so pairs cancel out
print(single) # 4Augmented assignment
x += 1, -=, *=, /=, //=, %=, **=, &=, |=, ^=, <<=, >>=, @=. For mutable objects they modify in place (__iadd__); for immutable ones they build a new object and rebind the name.
a = [1]
b = a
a += [2] # list.__iadd__ → extends the same list
print(b) # [1, 2]
a = a + [3] # + builds a NEW list; b still sees the old one
print(a, b) # [1, 2, 3] [1, 2]Conditional expression & walrus
age = 20
print("adult" if age >= 18 else "minor") # adult
data = [4, 9, 1, 7]
if (n := len(data)) > 3: # assign and test in one step
print(f"{n} items") # 4 items
big_squares = [y for x in data if (y := x * x) > 10]
print(big_squares) # [16, 81, 49]Membership, identity & overloading
print("ell" in "hello", 3 in {1, 2, 3}, "a" in {"a": 1}) # True True True
a, b = [], []
print(a == b, a is b, a is not b) # True False True
print("ab" * 3, [0] * 3, [1] + [2]) # ababab [0, 0, 0] [1, 2]
import operator
print(operator.add(2, 3), operator.mul("ha", 2)) # 5 hahaOperators are method calls in disguise: a + b → a.__add__(b), a < b → a.__lt__(b), x in c → c.__contains__(x). That's how str, list and your own classes give + and * their own meaning (see Magic (Dunder) Methods). The operator module exposes each one as a function for sorted(key=…), reduce and map.
Common pitfalls
x = 5
print(x == 1 or 2) # 2 ← parsed as (x == 1) or 2 → always truthy!
print(x in (1, 2)) # False ← what was meant
print(not x == 5, x != 5) # False False ← not binds looser than ==
print(-3 ** 2) # -9 ← -(3 ** 2)
print(0.1 + 0.2 == 0.3) # False ← floats; compare with math.isclose
print(1 + 2 * 3, (1 + 2) * 3) # 7 9What do and and or return?
Why is -7 // 2 equal to -4 in Python?
How do you check whether a number is a power of two?
What does 1 < 2 == 2 evaluate to?