Basic Operators

Concepts covered: Arithmetic, Boolean Operators

The 7 arithmetic operators

Arithmetic on ints and floats uses 7 operators, +, -, *, /, //, % and **, and the result's type depends on the operator as much as on the operands. On 2 ints, +, -, *, // and % return an int, and so does ** with a non-negative exponent, however large the result: Python integers have no overflow, so 2 ** 100 is a 31-digit number. A negative exponent gives a float, so 2 ** -1 is 0.5, and any operation with a float operand returns a float. True division / always returns a float, even when exact, so 14997 / 3 is 4999.0.

// is floor division and % is modulo, and the 2 are defined together so that a == (a // b) * b + a % b holds for every pair of operands. Floor division rounds toward negative infinity rather than toward 0, so -7 // 2 is -4 rather than -3, and the remainder takes the sign of the divisor: -7 % 2 is 1. That pairing is what makes % safe for wrapping an index or a weekday around, and it differs from C and Java, where the remainder takes the sign of the dividend.

subtotal_cents = 14997
quantity = 3

print(subtotal_cents / quantity)
print(subtotal_cents // quantity)
print(subtotal_cents % quantity)
print(-7 // 2, -7 % 2)
print(2 ** 10)
print(0.1 + 0.2 == 0.3)
print(quantity >= 3 and subtotal_cents > 10000)

Output:

4999.0
4999
0
-4 1
1024
False
True

The first 3 lines are the 3 answers to the same division: the quotient as a float, the quotient as a whole number, and what was left over, which is 0 because 3 units at 4999 cents each sum to exactly 14997. The sixth line prints False because 0.1 + 0.2 rounds to 0.30000000000000004 while the literal 0.3 rounds to a different double. Float equality is reliable only when both sides were produced the same way, which is one more reason to keep money in integer cents and compare the ints.

Comparison and boolean operators

The 6 comparison operators ==, !=, <, <=, > and >= return a bool, and they chain: 10000 < subtotal_cents <= 20000 tests both conditions at once, with subtotal_cents evaluated once. Comparing an int with a float works numerically, so 3 == 3.0 is True. Comparing an int with a str for order raises TypeError: '<' not supported between instances of 'int' and 'str', and for equality returns False without complaint: 3 == "3" is False, the text-versus-number mismatch wearing a different operator.

The boolean operators are and, or and not. They combine conditions and short-circuit: quantity > 0 and total / quantity > 100 never divides when the quantity is 0, because and stops at the first falsy operand. They also return an operand rather than a plain True or False, so amount or 100 substitutes a default of 100 when a field is None. The trap is that a real reading of 0.0 is falsy too and becomes 100, while 100 if amount is None else amount replaces only the missing value.

Precedence and augmented assignment

Operators bind in a fixed order, and -2 ** 2 is -4 because the power binds tighter than the unary minus, while 3 + 4 * 2 is 11 because multiplication binds tighter than addition. Parentheses cost nothing and remove the question, so (subtotal_cents * 85) // 100 reads the intent even where they change nothing. Augmented assignment, total += amount, evaluates the right side, applies the operator to the current value and rebinds the name, and every arithmetic operator has one: -=, *=, //=, %=.

LevelOperatorsExample
Binds first`**``-2 ** 2` is -4
2unary `-``-x * 2` negates first
3`*`, `/`, `//`, `%``3 + 4 * 2` is 11
4`+`, `-``10 - 2 - 3` is 5, left to right
5`==`, `!=`, `<`, `<=`, `>`, `>=``1 + 2 < 4` is True
6`not``not 3 > 4` is True
7`and``a or b and c` is `a or (b and c)`
Binds last`or``x or y` returns the first truthy

The broken line divides only discount_cents by 100, because / binds tighter than -, so the output is 14992.0, a cent total with 5 dollars subtracted from it. Wrapping the subtraction in parentheses makes the whole cent amount divide, and the result is 144.97 dollars. A bug like this prints a plausible number every time it runs, which is why a total that is 100 times too large is worth a parenthesis check before anything else.

About this lesson

This section is part of the Python Foundations: 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.