Python Operator Precedence and Bitwise Operators Explained

The Python operator precedence table from highest to lowest, and why minus two squared is -4. Bitwise tricks on unbounded ints, no ++, and the operator module.

  • Course: Python study plan
  • Module: Values, types and operators
  • Kind: Lesson
  • Reading time: 13 min
  • Runtime: CPython 3.11

What is the operator precedence in Python?

Python's operator precedence, from highest to lowest: brackets, then subscripts, calls and attributes, then **, unary + - ~, * / // % @, binary + -, shifts, &, ^, |, then every comparison including in and is at one level, then not, and, or, the conditional expression, lambda and :=. Operators associate left to right except **, which associates right to left.

Lesson

Python's operators are the usual set plus a few of its own — //, **, in, is, @, the walrus — and the precedence table is short enough to learn. What is worth learning precisely is the handful of places where the table produces something a reader does not expect: -2 ** 2, not a == b, a & b == c, and the bitwise operators applied to arbitrary-precision integers. This lesson gives the table, the semantics of the bitwise operators on unbounded ints, and the operator module that lets you pass an operator as a function.

The table, highest first

PrecedenceOperatorsNotes
1(…), […], {…}grouping and literals
2x[i], x[a:b], f(…), x.attrsubscript, slice, call, attribute
3await x
4**right-associative; binds tighter than unary minus on its left
5+x, -x, ~xunary
6*, @, /, //, %
7+, -binary
8<<, >>shifts
9&bitwise and
10^bitwise xor
11`\`bitwise or
12in, not in, is, is not, <, <=, >, >=, !=, ==comparisons — all one level, and they chain
13not x
14and
15or
16x if c else yconditional expression
17lambda
18:=walrus

Three consequences are worth memorising. ** is right-associative: 2 ** 3 ** 2 is 2 ** 9 = 512, not 64. -2 ** 2 is -(2 ** 2) = -4, because the unary minus is lower than **; but 2 ** -1 is 0.5, because the exponent position takes a unary expression. And the bitwise operators sit above comparisons, so a & b == c parses as (a & b) == c — the reverse of C, Java and JavaScript, where a & b == c is a & (b == c); parenthesise anyway, for the reader who knows those languages. Comparisons sit above not, so not a == b is not (a == b), which is what you meant; not a in xs works the same way but a not in xs is the readable spelling.

Everything else associates left to right: 10 - 4 - 3 is 3, 100 / 10 / 2 is 5.0, a % b % c is (a % b) % c.

Arithmetic

+ - * / // % ** are the previous lessons' subject; @ is matrix multiplication, defined by NumPy arrays and by your own classes through __matmul__, and unused by the built-in types. + on sequences concatenates ([1] + [2], "a" + "b") and * with an int repeats ([0] * 5, "-" * 20). The augmented forms +=, -=, *=, /=, //=, %=, **=, &=, |=, ^=, <<=, >>= exist for every binary operator; there is no ++ or -- (++n parses as +(+n), a no-op, silently).

Bitwise operators on unbounded integers

&, |, ^, ~, <<, >> treat an int as a two's-complement number with infinitely many bits. Positive numbers behave as in any language: 0b1100 & 0b1010 is 0b1000, 1 << 40 is 1099511627776 (no overflow), x >> 1 halves toward negative infinity. ~x is -x - 1, so ~5 is -6, and a negative number has an infinite run of leading ones, which is why -1 & 0xFF is 255 — masking selects the low bits exactly as you would want.

The idioms interviews expect:

x & 1                # 1 if odd
x & (x - 1)          # clears the lowest set bit; zero iff x is a power of two (x > 0)
x & -x               # isolates the lowest set bit
x | (1 << k)         # set bit k
x & ~(1 << k)        # clear bit k
x ^ (1 << k)         # toggle bit k
(x >> k) & 1         # read bit k
x.bit_count()        # number of set bits (3.10); bin(x).count("1") before that
x.bit_length()       # bits needed: (255).bit_length() == 8

Flags are sets of bits: READ, WRITE, EXEC = 1, 2, 4; a permission set is READ | EXEC; testing is perms & WRITE, which is 0 or WRITE — truthy either way for if, but compare with != 0 or == WRITE when a boolean must be stored. enum.Flag gives these a type (Module 13).

Comparisons, membership, identity

==, !=, <, <=, >, >= compare values and chain (0 <= i < n). in and not in test membership — of an element in a container, a substring in a string, a key in a dict. is and is not test identity (Module 2 lesson 3). Comparing different types with < raises TypeError (3 < "3"); == between different types is simply False. Sequences compare lexicographically: [1, 2] < [1, 3], "abc" < "abd", (1, "b") < (1, "c") — the rule that makes sorting tuples by several keys work (Module 6).

The operator module

Every operator has a named function in operator: operator.add, mul, floordiv, neg, lt, eq, and_, or_, contains, getitem. They are what you pass to functools.reduce, map or sorted(key=…) when a lambda would only wrap an operator: reduce(operator.mul, xs, 1) is the product. operator.itemgetter(1) and attrgetter("name") build key functions (Module 11).

Evaluating from text

An expression written as a string can be evaluated with eval, and a program that reads expressions from untrusted input must not — eval("__import__('os').system('rm -rf /')") is why. For arithmetic on trusted, small input it is a reasonable tool, and ast.literal_eval safely parses literals only (numbers, strings, tuples, lists, dicts) without evaluating code, which is the right way to turn "[1, 2, 3]" back into a list.

Pitfalls

  • -2 ** 2 is −4; 2 ** 3 ** 2 is 512.
  • Reading a & mask == 0 with C's rules: in Python it is already (a & mask) == 0, but write the brackets — code is read by people who know C.
  • ++i does nothing; i += 1.
  • 3 < "3" is a TypeError; parse first.
  • x is not None and x > 0 needs no parentheses, but not x in xs should be x not in xs.
  • eval on input you did not write.

Key takeaways

  • ** binds tightest among arithmetic and associates right; unary minus is below it; bitwise operators are above comparisons.
  • Comparisons chain and sit above not, and, or, which sit above the conditional expression.
  • Bitwise operators work on infinite two's-complement integers; x & (x - 1), 1 << k, bit_count are the idioms.
  • == across types is False, < across types is an error; sequences compare lexicographically.
  • operator names every operator as a function; ast.literal_eval parses literals safely.

Common questions

Why is -2 ** 2 equal to -4 in Python?

Because ** binds tighter than a unary minus on its left, so -2 ** 2 parses as -(2 ** 2). Write (-2) ** 2 to get 4. ** is also right-associative: 2 ** 3 ** 2 is 2 ** 9, which is 512, not 64.

Does Python have ++ and -- operators?

No. Write i += 1 and i -= 1. ++i is not an error but parses as +(+i), two unary pluses that leave the value unchanged, so it silently does nothing, while i++ is a syntax error.

How do bitwise operators work on negative numbers in Python?

Python treats an int as two's complement with infinitely many bits, so a negative number has an endless run of leading ones. ~x equals -x - 1 (~5 is -6), and a mask selects the low bits as expected: -1 & 0xFF is 255. Shifts never overflow: 1 << 40 is exact.

How do I check if a number is a power of two in Python?

For x > 0, test (x & (x - 1)) == 0. Subtracting 1 flips the lowest set bit and every bit below it, so the AND clears that bit, and only a power of two has no other bit set. x.bit_count() == 1, from Python 3.10, says the same.

Is eval safe to use in Python?

Not on input you did not write: eval runs any Python expression, so untrusted text can execute arbitrary code, such as a call that deletes files. To turn text like "[1, 2, 3]" back into a value, use ast.literal_eval, which parses literals only — numbers, strings, tuples, lists, dicts — and evaluates no code.

Exercises

Permission flags

Model a permission set as bits: read is 1, write is 2, exec is 4. The first line lists the permissions initially granted (possibly none). Then n commands follow: has <perm> prints yes or no using &; add <perm> sets a bit with |; remove <perm> clears it with & ~; show prints the mask as three binary digits.

Input: a line of permissions, then n, then n commands. Output: one line per has and show.

read exec
4
show
has write
add write
show

prints

mask 101
no
mask 111

Precedence versus left to right

Read integer expressions written with spaces between tokens, using the operators + - * // % **. For each, print the value Python gives (evaluate it with eval — the input is trusted here) and the value a strictly left-to-right reading would give, applying each operator as it is met with no precedence at all.

Input: n, then n expressions. Output: <expression>: precedence <p>, left-to-right <l> per line.

2
2 + 3 * 4
2 ** 3 ** 2

prints

2 + 3 * 4: precedence 14, left-to-right 20
2 ** 3 ** 2: precedence 512, left-to-right 64

In this module: Values, types and operators

← Conversions — between text, numbers and containers · Checkpoint — Values, types and operators →