Operators and Readability
Concepts covered: Arithmetic
When an expression holds several operators, Python applies them in a fixed order rather than left to right across the whole line. ** goes first. * and / share the next level with // and %. Below them sit + and -, and == comes last. Within one level, evaluation runs left to right, except for **, which runs right to left. Parentheses override all of it, and they're also the only way to tell a reader what you meant.
| Level | Operators | Direction | Example |
|---|---|---|---|
| 1 (first) | ( ) | innermost first | (2 + 3) * 4 gives 20 |
| 2 | ** | right to left | 2 ** 3 ** 2 gives 512 |
| 3 | - (sign) | applies to the operand beside it | -2 ** 2 gives -4 |
| 4 | * / // % | left to right | 100 / 10 / 2 gives 5.0 |
| 5 | + - | left to right | 10 - 4 - 3 gives 3 |
| 6 (last) | == | after all arithmetic | 2 + 3 == 5 gives True |
print(2 + 3 * 4)
print((2 + 3) * 4)
print(2 ** 3 ** 2)
print(-2 ** 2)
print(10 - 4 - 3)
print(100 / 10 / 2)
print(2 + 3 == 5)Output:
14 20 512 -4 3 5.0 True
Line 3 is the surprising one: 2 ** 3 ** 2 is 2 ** 9, which is 512, while (2 ** 3) ** 2 would be 64. Line 4 is the other: the exponent binds tighter than the minus sign, so the result is the negative of 4. Both are legal, and both are the kind of line a colleague will misread, which is the reason to add parentheses even where Python does not need them.
Parentheses say what you meant
The run below computes a bill 2 ways. The first adds tax on top of the subtotal, the second doubles the subtotal and takes a quarter of that, and the only difference on the page is a pair of parentheses.
price = 20
qty = 3
tax_rate = 0.25
subtotal = price * qty
total = subtotal + subtotal * tax_rate
print(total)
wrong = (subtotal + subtotal) * tax_rate
print(wrong)75.0 30.0
Name the steps
A long expression is right or wrong in one go, and a reader has to hold every intermediate value in their head to check it. Breaking it into named steps gives each value a name, lets you print any step while you're investigating, and makes the operator order a smaller concern because each line holds 1 or 2 operators at most. The 2 programs below print the same number, 37.5.
print((20 * 3 + 20 * 3 * 0.25) * (1 - 0.5))unit_price = 20
quantity = 3
tax_rate = 0.25
discount = 0.5
subtotal = unit_price * quantity
with_tax = subtotal + subtotal * tax_rate
total = with_tax * (1 - discount)
print(total)Spacing and layout
Python ignores spaces inside an expression: a*b+c runs the same as a * b + c. The convention is 1 space on each side of = and ==. The lower-precedence operators get the same spacing, while a higher-precedence operator loses its spaces so the grouping shows: a*b + c. A line longer than about 80 characters gets split by naming part of it, as above.
- Do
- Add parentheses wherever 2 operators of different levels meet
- Put 1 space around =, == and the + or - of an expression
- Name an intermediate result if the line needs explaining
- Keep and a minus sign apart with parentheses: (-2) 2 or -(2 ** 2)
- Avoid
- Rely on readers knowing that ** runs right to left
- Pack 6 operators into one print call
- Mix spaced and unspaced operators at the same level: a+b * c
- Reuse a name for a different quantity 2 lines later
What does this program print?
base = 10
bonus = 5
years = 2
print(base + bonus * years ** 2)- 60
- 900
- 40
- 30
Capstone practice
Each program below pulls on more than one section at once, so expect naming and the assignment-versus-comparison question to turn up in the same lines as type mixing and operator order.
A fixed fee plus a per-item cost needs no parentheses, because * runs before +: 5.0 + 4 * 1.5 multiplies to 6.0 first and sums to 11.0. Swap the 2 operators and 5.0 * 4 + 1.5 gives 21.5. Working the line through with real numbers shows whether each operator sits where it belongs.
String operators share the same precedence. In "-" * 3 + "x" the repetition runs first and produces ---. The join then gives ---x. Writing "x" + "-" * 3 gives x--- for the same reason: the * on the right finishes before the join begins.
About this lesson
This section is part of the Python Expressions: Beginner lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.