Skip to content
VLSI Mentor

Python Part I · Module 3 · Operators and Expressions

Precedence, Parentheses and Saying What You Mean

Three chapters in this module have deferred the same question. When an expression contains more than one operator, which one does Python apply first? This chapter answers it, and then argues that knowing the answer is not usually the point. Python does have a defined order, and a handful of those rules are worth carrying in your head because they come up constantly. Beyond that handful, the professional response to an expression whose order is not obvious is not to prove you can work it out — it is to add parentheses so that nobody else has to. This is the last chapter of Module 3, and it closes with the habit that makes everything you have learned readable to the next engineer.

Foundation10 min readPythonPart IFundamentalsPrecedenceReadability

Part I · Module 3 · Chapter 3.8 · Precedence, Parentheses and Saying What You Mean

1. The Problem

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
print(2 + 3 * 4)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
14

Not 20. If Python worked strictly left to right it would add first — 2 + 3 is 5, times 4 is 20. It did not.

Python applied the multiplication first, then the addition:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   2 + 3 * 4
        ↓        multiplication binds more tightly
   2 +  12
        ↓
      14

This is precedence: some operators bind more tightly than others, and the tighter ones are applied first. It is the same rule you learned for arithmetic at school, and Python follows the conventional one.

2. Parentheses Win

Parentheses group part of an expression so it is worked out as a unit:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
print(2 + 3 * 4)
print((2 + 3) * 4)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
14
20

Chapter 3.1 §5 used this to show the order explicitly, precisely so that precedence did not have to be assumed. Now it can be named: whatever is inside parentheses is worked out first, whatever the operators involved.

3. The Rules Worth Knowing

There is a full precedence order in Python, and most of it is not worth memorising. Four groupings cover nearly everything you will meet.

Arithmetic before comparison. The arithmetic is done, then the comparison asks about the result.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
total = 600
passed = 589
print(total - passed == 11)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
True

total - passed produced 11, and then == 11 compared it. That is Chapter 3.4 §7, now explained.

Comparison before and / or. Each comparison produces its bool, then the logical operator combines them.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
error_count = 0
coverage = 96.2
print(error_count == 0 and coverage >= 95.0)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
True

Both comparisons were evaluated first. This is why Chapter 3.5 §3 needed no brackets.

not before and, and and before or.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
print(True or False and False)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
True

The and was applied first, giving False, and then True or False gave True. Had the or gone first, the answer would have been False.

Within arithmetic: ** binds tightest, then * / // %, then + -.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
print(2 + 3 ** 2)
print(2 * 3 ** 2)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
11
18

The power was applied before the addition and before the multiplication in each case.

Here they are compressed. This table is for reference, not memorisation — the four statements above are what you actually carry.

Binds tightestOperators
1() — always wins
2**
3~, unary -
4* / // %
5+ -
6<< >>
7&
8^
9|
10== != < <= > >= in not in is is not
11not
12and
13 (loosest)or

4. The One Where Python Differs From C

Look at rows 7 and 10. In Python the bitwise operators bind more tightly than the comparisons.

That is the sensible order, and it means the obvious way to test a masked bit works as written:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
flags = 0b1010
print(flags & 0b0010 == 0b0010)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
True

Python grouped it as (flags & 0b0010) == 0b0010 — mask first, then compare — which is what the line looks like it means.

C orders these two the other way round. In C, == binds tighter than &, so the identical-looking line groups as flags & (0b0010 == 0b0010), which is a completely different question. You can make Python do that too, by asking for it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
flags = 0b1010
print(flags & (0b0010 == 0b0010))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
0

The comparison produced True, and flags & True is a bitwise operation against 1, giving 0.

5. Parentheses Are for Readers

Here is the argument this chapter actually wants to make.

Parentheses are usually introduced as a way to override precedence. That is one job. The more valuable one is that they let a reader stop thinking.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
error_count = 0
finished = True
timed_out = False

print(error_count == 0 and finished and not timed_out)
print((error_count == 0) and (finished and not timed_out))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
True
True

Identical results. The second version changes nothing Python does — and it tells a reader, instantly, that the question has two halves, without their having to recall where not sits relative to and.

That is worth the four characters.

A few cases where brackets earn their place even though the expression is already correct:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = 0b10110110

print(status & (1 << 4))
print((status & 0b1111) == 0b0110)
print((600 - 589) / 600)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
16
True
0.018333333333333333

The first two were discussed above. The third does not need brackets at all — - binds tighter than / — but bracketing the subtraction says this is a difference, and then a rate, which is what the line means.

6. What Not to Do

Two failure modes, in opposite directions.

Do not write expressions that depend on obscure precedence. If a line is correct only because of a rule you had to look up, the next reader will have to look it up too — and one of you will eventually get it wrong.

Do not bracket everything either. This is not an improvement:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
print(((2) + ((3) * (4))))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
14

Brackets that do not group anything a reader needed grouped are noise, and noise hides the brackets that matter.

The target is in between: bracket where the order is not obvious, leave it alone where it is.

7. Predict, Run, Observe

Predict each, then run.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
print(2 + 3 * 4)
print((2 + 3) * 4)
print(2 ** 3 * 2)
print(10 - 4 - 3)
print(600 - 589 == 11)
print(True or False and False)
print((True or False) and False)
print(0b1010 & 0b0010 == 0b0010)
print(0b1010 & (0b0010 == 0b0010))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
14
20
16
3
True
True
False
True
0

Two to check yourself on. Lines 6 and 7 differ because bracketing forced the or first. Lines 8 and 9 differ because the second one asks for the C grouping — the comparison is done first and its True is then used as a number.

8. Exercise

Exercise 1 — make it explicit. Each of these is correct. Add parentheses that change nothing but make the intent obvious to a reader: (a) total - passed == 11 (b) error_count == 0 and finished (c) 2 + 3 * 4

Exercise 2 — the two groupings. Predict both, then run:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
flags = 0b1100
print(flags & 0b0100 == 0b0100)
print(flags & (0b0100 == 0b0100))

One is the bit test you meant. Say which, and which of the two a C programmer would have got by writing the first line.

Exercise 3 — predict the pair. Predict both, then run:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
print(True or False and False)
print((True or False) and False)

Say in one sentence which operator Python applied first in the unbracketed version.

Exercise 4 — the review question. A colleague submits this line. It is correct. Would you approve it as written, ask for brackets, or ask for it to be split across two lines? Justify in one sentence:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ready = error_count == 0 and coverage >= 95.0 and not timed_out

Exercise 5 — over-bracketed. Rewrite this so it says the same thing with only the brackets that help:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
print((((600) - (589)) / (600)))

9. Summary

  • Precedence decides which operator is applied first when several appear in one expression. Python uses the conventional arithmetic order.
  • Parentheses always win, and whatever is inside them is worked out first.
  • Four rules cover almost everything: arithmetic before comparison; comparison before and/or; not before and before or; and ** before * / // % before + -.
  • Bitwise operators bind tighter than comparisons — so value & mask == x masks first, as it looks. C groups it the other way round, so bracket it in both languages if you move between them.
  • Parentheses are a readability tool, not only an override. Add them where a reader would otherwise have to work out the order.
  • Do not bracket everything. Noise hides the brackets that matter.
  • Precedence puzzles are not a skill. An expression that needs a lookup should be rewritten, not decoded.

That completes Module 3 — Operators and Expressions. You can now build expressions from every operator family Python provides, predict both the value and the type they produce, reason about bits as well as quantities, and write expressions a colleague can read without stopping.

Everything so far has worked on one value at a time. The next module takes the value type you have used most — text — and shows what you can actually do with it: reaching individual characters, taking pieces out, searching, splitting a line into fields. Module 4 — Strings is where a line from a log file starts becoming something a script can take apart.

Where this fits

Part of the Python curriculum.