Python operators — theory with the uni cafeteria, // and % for sharing things out and a 0.1 + 0.2 that is not 0.3 (and the sandwich bill that never added up)
The first time I used Python for something “real” was in the uni cafeteria. Laura and I had ordered a coffee (1.10 €) and a sandwich (2.20 €), we put 3.30 € on the table and, since we had just covered variables in FP1 (my first-year programming course), I wrote a five-line program to check we had paid the right amount. This is what I wrote:
# My first "cafeteria program": splitting a coffee and a sandwich
coffee = 1.10 # euros
sandwich = 2.20
total = coffee + sandwich
print("Total:", total)
paid = 3.30 # what we put on the table, counted by hand
print("Paid exactly?", paid == total)
per_person = total / 2
print("Each:", per_person)
And this is what Python answered:
Total: 3.3000000000000003 Paid exactly? False Each: 1.6500000000000001
3.3000000000000003? We had not paid exactly? And 1.6500000000000001 each? The computer was not broken and Python does not add up badly: the problem was how I had used the operators. + and / on decimals, and a == to compare two numbers that “look” equal but are not. By the end of this article you will know exactly what happened and the three ways to avoid it.
In the variables and data types article you learned to store data in labelled boxes (int, float, str, bool), and I left you two promises: to explain //, % and ** (and why 5 / 2 gives 2.5) and to show you how to compare decimals safely. Today I keep them. We are going to see every operator you need in your first year: arithmetic, comparison, logical and compound assignment operators, plus the order in which Python applies them. All with the uni cafeteria as the example: prices, croissants that have to be shared out on trays and the till that fills up through the morning. Then, in the practice, you will use them in three complete programs.
Table of Contents
What is an operator in Python?
An operator is a symbol that tells Python what to do with one or more values. In 3 + 5, the + is the operator and 3 and 5 are its operands. The whole thing (3 + 5) is an expression, and an expression always boils down to a single value: 8.
Notice something that looks trivial but is not: the result of an expression has a type. 3 + 5 gives an int, 5 / 2 gives a float and 5 > 3 gives a bool. Knowing which type comes out of each operator saves you half the mistakes in this topic.
| Family | Operators | What they return | Example |
|---|---|---|---|
| Arithmetic | + - * / // % ** | A number | 120 + 95 → 215 |
| Comparison | == != < > <= >= | True or False | 120 < 150 → True |
| Logical | and or not | One of their operands (usually a bool) | True and False → False |
| Compound assignment | += -= *= /= //= %= **= | Nothing: they change a variable | till += 120 |
We will go through them in this order, which is also the order you will use them in: first you calculate, then you compare and then you combine comparisons.
Arithmetic operators in Python: the everyday ones
There are seven. To see them with real data I will use the cafeteria prices in cents (a coffee costs 120 cents, a croissant 95). Later you will see that working in cents is not a quirk of mine: it is the professional way of handling money.
# The seven arithmetic operators with cafeteria prices, in cents
coffee = 120 # 1.20 €
croissant = 95 # 0.95 €
# f"{expression = }" prints the expression as written and its result
print(f"{coffee + croissant = }") # addition
print(f"{coffee - croissant = }") # subtraction
print(f"{3 * coffee = }") # product
print(f"{coffee / 2 = }") # true division: ALWAYS gives a float
print(f"{coffee // 50 = }") # floor division: how many 50-cent coins fit
print(f"{coffee % 50 = }") # remainder: what is left after those coins
print(f"{2 ** 10 = }") # power
print(f"{9 ** 0.5 = }") # exponent 0.5 = square root
When you run it:
coffee + croissant = 215 coffee - croissant = 25 3 * coffee = 360 coffee / 2 = 60.0 coffee // 50 = 2 coffee % 50 = 20 2 ** 10 = 1024 9 ** 0.5 = 3.0
f"{expression = }", with the = just before the closing brace, prints the expression as written and its result. It is perfect for quick tests: you do not have to type the label by hand and it never gets out of sync with the calculation.
Between the lines:
coffee + croissantandcoffee - croissantdo what you expect: 120 + 95 = 215 and 120 − 95 = 25. As both operands areint, the result is also anint.3 * coffeemultiplies: three coffees are 360 cents.coffee / 2is ordinary division, the calculator one. Notice it gives60.0, with its.0, even though 120 divided by 2 is exact. We will see why in a moment.coffee // 50is floor division: how many 50-cent coins fit completely into a coffee. Two fit (2 × 50 = 100).coffee % 50is the remainder: what is left after putting down those two coins. 120 − 100 = 20.2 ** 10is the power: 2 to the power of 10, 1024. And9 ** 0.5is a trick worth knowing: raising to 0.5 is taking the square root, so it gives3.0.
Classic mistake 1: confusing / with //
This is the mistake I saw most often in the FP1 exercises, and the promise I left you in the variables article: why does 5 / 2 give 2.5? Because in Python 3 the / operator is always true division: the result is a float, whether there are decimals or not. If you come from C or Java, where 5 / 2 between integers gives 2, this one will catch you for sure.
If what you want is to know how many times one number fits into another, you need //. Let’s share out 17 croissants on trays of 5:
# Sharing out 17 croissants on trays of 5
croissants = 17
per_tray = 5
trays = croissants // per_tray # how many trays are filled completely
left_over = croissants % per_tray # how many are left over
print(trays, "full trays, left over:", left_over)
print("Check:", trays * per_tray + left_over) # it has to give 17 again
print("divmod does both:", divmod(croissants, per_tray))
# With / the type and the meaning change: you cannot carry 3.4 trays
print("17 / 5 =", croissants / per_tray)
print("10 / 2 =", 10 / 2, type(10 / 2)) # exact, but a float anyway
print("10 // 2 =", 10 // 2, type(10 // 2))
print("7.5 // 2 =", 7.5 // 2) # if an operand is a float, // gives a float
# // rounds DOWN (towards minus infinity), not towards zero
print("-7 // 2 =", -7 // 2)
print("-7 % 2 =", -7 % 2)
print("int(-7 / 2) =", int(-7 / 2)) # int() cuts the decimals: towards zero
This is what it prints:
3 full trays, left over: 2 Check: 17 divmod does both: (3, 2) 17 / 5 = 3.4 10 / 2 = 5.0 <class 'float'> 10 // 2 = 5 <class 'int'> 7.5 // 2 = 3.0 -7 // 2 = -4 -7 % 2 = 1 int(-7 / 2) = -3
The first four lines of output are the ones you will use the most in your life:
17 // 5gives3: 3 trays are filled completely.17 % 5gives2: 2 croissants are left over.- The check
trays * per_tray + left_overgives 17 again (3 × 5 + 2 = 17). This equality always holds, and it is the best way to understand what//and%are: the quotient and the remainder from primary-school division. divmod(17, 5)does both at once and returns the pair(3, 2). You will use it in the exercises to give change.
On the other hand, 17 / 5 gives 3.4, which is the correct answer to a different question: you cannot carry 3.4 trays to the counter. And look at the type lines: 10 / 2 gives 5.0 of type float, while 10 // 2 gives 5 of type int. Same value, different type.
Look at the drawing: at the top, the croissants being shared out; at the bottom, what happens with negative numbers, which is where // fools you.
| I want… | Operator | Example | Result |
|---|---|---|---|
| An average, a price per person, a percentage | / | 120 / 2 | 60.0 (float) |
| How many complete groups fit | // | 17 // 5 | 3 |
| What is left after sharing out | % | 17 % 5 | 2 |
| Both at once | divmod | divmod(17, 5) | (3, 2) |
// does not drop the decimals: it rounds down. With positive numbers it is the same thing, but -7 // 2 gives -4, not -3, because −3.5 rounded down is −4. If what you want is to cut off the decimals (going towards zero), use int(-7 / 2), which gives -3. And if one operand is a float, // returns a float: 7.5 // 2 gives 3.0.
Classic mistake 2: % is not percentage
When you see % in Python, it does not mean “per cent”. It means modulo, the remainder of floor division. 120 % 50 is not “50 % of 120” (that would be 60); it is what is left when you take 50 away from 120 as many times as it fits: 20.
What is something so odd good for? For much more than it seems:
- Even or odd:
n % 2 == 0isTrueifnis even. If the remainder of dividing by 2 is 0, nothing is left over. - Divisible by another number:
15 % 3 == 0isTrue;16 % 3 == 0isFalse(1 is left over). - The last digit of a number:
2847 % 10is7. And2847 // 10drops that last digit (284). Combining both you will get every digit out in the exercises. - Formatting money: if you have 1091 cents,
1091 // 100are 10 euros and1091 % 100are 91 cents. You will do it in the practice.
To calculate a real percentage, multiply and divide: 15 % of 1200 is 1200 * 15 / 100 (or 1200 * 15 // 100 if you want an integer).
With negative numbers, Python’s remainder takes the sign of the divisor: -7 % 2 gives 1, and 5 % -2 gives -1. It looks capricious, but it is what makes b * (a // b) + a % b == a always hold: 2 × (−4) + 1 = −7. In the practice you will check it with −17 and 5.
Comparison operators: they return True or False
Comparison operators ask something about two values and answer with a bool: True or False. They are the basis of every decision you will make in the next topic.
| Operator | Means | Example with price = 120 | Result |
|---|---|---|---|
== | equal to | price == 120 | True |
!= | not equal to | price != 100 | True |
< | less than | price < 150 | True |
> | greater than | price > 150 | False |
<= | less than or equal to | price <= 120 | True |
>= | greater than or equal to | price >= 200 | False |
# Comparison operators: they always return True or False
price = 120 # cents
budget = 150
print(f"{price < budget = }")
print(f"{price == 120 = }")
print(f"{price != 100 = }") # != means "not equal to"
print(f"{0 <= price <= 200 = }") # chained comparison: inside the range
print(f"{'coffee' == 'Coffee' = }") # capital letters count
print(f"{5 == 5.0 = }") # int and float with the same value: equal
print(f"{'5' == 5 = }") # text versus number: False, no error
print(f"{'coffee' < 'juice' = }") # texts: alphabetical order
Real output:
price < budget = True price == 120 = True price != 100 = True 0 <= price <= 200 = True 'coffee' == 'Coffee' = False 5 == 5.0 = True '5' == 5 = False 'coffee' < 'juice' = True
What is worth a second look:
0 <= price <= 200is a chained comparison: Python reads it as0 <= price and price <= 200. It checks whether a value is inside a range, and it is much more readable than the version withand.'coffee' == 'Coffee'isFalse: for Python, a capital letter is a different character. If you compare what a user types, normalise it first.5 == 5.0isTrue: anintand afloatwith the same value are equal.'5' == 5isFalseand does not raise an error: a text is never equal to a number. It is exactly the silent bug from the variables article, when a value arrives frominput()as text and you compare it with a number.'coffee' < 'juice'isTrue: texts are compared in alphabetical order (character by character, by their code, to be precise).
Not equal in Python: the != operator
A lot of people search for how to write “not equal” or “different from” in Python. It is !=, an exclamation mark stuck to an equals sign. It reads “is not equal to” and returns the opposite of ==: price != 100 is True because 120 is not 100. There is no <> (Python 2 had it; in Python 3 it is a SyntaxError) and no =!.
A very common use: divisor != 0 before dividing, which you will see in a moment with the logical operators.
Classic mistake 3: confusing = with ==
= stores a value in a variable. == asks whether two values are equal. They look so alike that, in a hurry, one slips in for the other. Look what happens if you write = instead of == in a condition:
price = 120
if price = 120:
print("It is a coffee")
And the result:
File "assign.py", line 2
if price = 120:
^^^^^^^^^^^
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?
The good news is that Python 3 spells it out: “Maybe you meant ‘==’ … instead of ‘=’?”. The little ^^^^ arrows point at the part it does not understand. The bad news is that elsewhere the error does not show up: if you write price == 120 on a line of its own meaning to assign, Python compares, stores nothing and carries on happily.
Read it out loud. = reads “is set to” or “store” (price = 120: price is set to 120). == reads “is it equal to?” (price == 120: is price equal to 120?). If the sentence is a question, it is two equals signs.
Comparing decimals safely: why 0.1 + 0.2 is not 0.3
Back to the hook. The receipt did not add up because 1.10 + 2.20 gave 3.3000000000000003. The most famous case of the same problem is this one:
import math
# The problem: 0.1 and 0.2 cannot be stored exactly in binary
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
# With 20 decimal places you see what is really stored
print(f"{0.1:.20f}")
print(f"{0.2:.20f}")
print(f"{0.1 + 0.2:.20f}")
print(f"{0.3:.20f}")
# Solution 1: round before comparing
print(round(0.1 + 0.2, 2) == 0.3)
# Solution 2: math.isclose compares with a tolerance
print(math.isclose(0.1 + 0.2, 0.3))
print(math.isclose(1.10 + 2.20, 3.30)) # the receipt from the hook
# Solution 3: work in cents (integers, which are exact)
print(10 + 20 == 30)
print(110 + 220 == 330)
When you run it:
0.30000000000000004 False 0.10000000000000000555 0.20000000000000001110 0.30000000000000004441 0.29999999999999998890 True True True True True
What is going on? The computer stores float values in binary, and in binary 0.1 has no exact representation: it is like 1/3 in decimal (0.3333…), which never ends. So Python stores the closest number it can. With 20 decimal places you can see it: 0.1 is actually 0.10000000000000000555 and 0.2 is 0.20000000000000001110. When you add them, the tiny errors add up and the result (0.30000000000000004441) does not land in the same place as the 0.3 you type by hand (0.29999999999999998890).
As the drawing shows, the difference is tiny (about 0.00000000000000005), but == demands that both values are exactly the same point on the line. That is why it gives False. And it is not a Python bug: it happens in Java, in C, in JavaScript and on your scientific calculator if it looks at enough decimal places.
You have three ways to defend yourself, and all three appear in the program:
- Round before comparing:
round(0.1 + 0.2, 2) == 0.3givesTrue. It works when you know how many decimal places matter (two, for money). - Compare with a tolerance:
math.isclose(a, b)returnsTrueif the two numbers are close enough. You needimport mathat the top. It is the right way to compare results of calculations with decimals, and it is what fixes the receipt from the hook:math.isclose(1.10 + 2.20, 3.30)givesTrue. - Do not use decimals: work in cents, with integers.
110 + 220 == 330is always exact, becauseintvalues do not have this problem. It is what banks and online shops do, and what you will do in the practice.
| Situation | What to use | Example |
|---|---|---|
| Money | Cents (int) | 110 + 220 == 330 |
| Results of calculations with decimals | math.isclose | math.isclose(average, 7.3) |
| Only a few decimal places matter | round | round(total, 2) == 3.3 |
| Showing it on screen | Formatting, not round | f"{total:.2f}" → 3.30 |
Never compare two float values with == (or !=) if they come from a calculation. It will work with some data and fail with other data, and that kind of bug is the worst to track down.
Logical operators: and, or and not
Comparisons answer single questions. To combine them (“is it open and is there no queue?”) you use the logical operators:
a | b | a and b | a or b | not a |
|---|---|---|---|---|
True | True | True | True | False |
True | False | False | True | False |
False | True | False | True | True |
False | False | False | False | True |
In short: and is only true if both are; or is true if at least one is; not flips it. So far, what you find in any book. Now comes what almost nobody explains in first year:
# Logical operators with the state of the cafeteria
is_open = True
queue = False
print(f"{is_open and not queue = }") # can I go in now?
print(f"{is_open or queue = }")
print(f"{not is_open = }")
# and and or do not always return True/False: they return one of their operands
name = "" # the customer did not give a name
print(f"{name or 'Anonymous' = }") # "" is falsy: or returns the second one
print(f"{'Laura' or 'Anonymous' = }") # "Laura" is truthy: it keeps it
print(f"{0 or 5 = }", f"{3 and 7 = }", f"{'' and 99 = }")
# Short-circuit: if the left side decides, the right side is NOT evaluated
customers = 0
till = 0
print(f"{customers != 0 and till / customers > 5 = }") # never gets to divide
print(f"{till / customers > 5 and customers != 0 = }") # divides first: error
This is what it prints:
is_open and not queue = True
is_open or queue = True
not is_open = False
name or 'Anonymous' = 'Anonymous'
'Laura' or 'Anonymous' = 'Laura'
0 or 5 = 5 3 and 7 = 7 '' and 99 = ''
customers != 0 and till / customers > 5 = False
Traceback (most recent call last):
File "logical.py", line 19, in <module>
print(f"{till / customers > 5 and customers != 0 = }") # divides first: error
~~~~~^~~~~~~~~~~
ZeroDivisionError: division by zero
and and or return values, not just True or False
Look at name or 'Anonymous': it does not give True or False, it gives 'Anonymous'. That is because in Python and and or return one of their operands:
x or y: ifxis “truthy”, it returnsx; otherwise it returnsy.x and y: ifxis “falsy”, it returnsx; otherwise it returnsy.
And what is “truthy” or “falsy” for something that is not a bool? You saw it in the variables article with bool(): 0, 0.0, the empty text "" and None are falsy; almost everything else is truthy. So:
name or 'Anonymous'withname = ""returns'Anonymous', because the empty text is falsy. With'Laura', it returns'Laura'. It is the shortest way to set a default value.0 or 5gives5;3 and 7gives7(3 is truthy, soandreturns the second one);'' and 99gives''(the empty text is falsy andandkeeps it).
When the operands are bool, as in is_open and not queue, none of this matters: the result is the good old True or False.
Short-circuit evaluation
The last two lines of the program are the most important. With customers = 0:
customers != 0 and till / customers > 5givesFalsewithout an error. Python looks at the left side first:customers != 0isFalse, and “false and anything” is false. So it does not even evaluate the right side. The division by zero never happens.till / customers > 5 and customers != 0has the same pieces the other way round, and it blows up withZeroDivisionError: Python starts on the left, tries to divide by zero and stops there.
This is called short-circuit evaluation: and stops as soon as it finds something false and or stops as soon as it finds something true. It is not an exam detail: it is a tool. Put the protecting check first (divisor != 0, “the list is not empty”…) and the dangerous operation after it.
| Operator | Stops when the left side is… | And then returns… |
|---|---|---|
and | falsy | the left side |
or | truthy | the left side |
Writing method == "cash" or "bizum" to ask “is it cash or bizum?”. Python reads it as (method == "cash") or "bizum", and since "bizum" is a non-empty text (truthy), the result is never false. You have to repeat the comparison: method == "cash" or method == "bizum". We take it apart in the exercises.
Compound assignment operators: the shortcut that saves time
Very often you want to change a variable based on its own value: add a sale to the till, count one more coffee. Writing till = till + 120 works, but Python has a shortcut: till += 120. There is one for every arithmetic operator.
# The cafeteria till through the morning (cents)
till = 0
coffees = 0
till += 120 # a coffee (till = till + 120)
coffees += 1
till += 95 # a croissant
till += 120 # another coffee
coffees += 1
till -= 50 # we give back 50 cents of wrong change
print("Till:", till, "| coffees sold:", coffees)
till *= 2 # "what if the whole morning were like this?"
print("Doubled:", till)
till //= 3 # split over 3 shifts (integer)
print("Per shift:", till)
till /= 2 # /= turns it into a float, even if the division is exact
print("Half an hour:", till, type(till))
Real output:
Till: 285 | coffees sold: 2 Doubled: 570 Per shift: 190 Half an hour: 95.0 <class 'float'>
This is how the till evolves line by line (the trace table I recommend you always make when a variable changes several times):
| Line | Operation | till after | coffees after |
|---|---|---|---|
| start | till = 0, coffees = 0 | 0 | 0 |
| coffee | till += 120, coffees += 1 | 120 | 1 |
| croissant | till += 95 | 215 | 1 |
| coffee | till += 120, coffees += 1 | 335 | 2 |
| refund | till -= 50 | 285 | 2 |
| doubled | till *= 2 | 570 | 2 |
| three shifts | till //= 3 | 190 | 2 |
| half an hour | till /= 2 | 95.0 | 2 |
The sums: 120 + 95 + 120 − 50 = 285; 285 × 2 = 570; 570 // 3 = 190 (exact); 190 / 2 = 95.0. Look at the last line of the output: after /=, the till is already a float, just as happened with /. The shortcuts behave exactly like the operator inside them.
+= is the operator you will type most in FP1: every counter (coffees += 1) and accumulator (total += price) in loops uses it. And it also works with texts: message += "!" adds an exclamation mark at the end.
Using += on a variable that does not exist yet. sales += 1 without having written sales = 0 first gives NameError, because Python needs the previous value to add 1 to it. Always initialise your counters.
Operator precedence: order matters
When an expression has several operators, which one goes first? As in maths, multiplication goes before addition. But Python has more operators than school maths, and some cases are surprising:
# Precedence: what is worked out first when there are several operators
print(3 + 8 * 2) # * before +
print((3 + 8) * 2) # parentheses rule
print(-2 ** 2) # ** before the leading -: -(2 ** 2)
print((-2) ** 2)
print(2 ** 3 ** 2) # ** groups from right to left: 2 ** 9
print(10 - 4 - 3) # same level: from left to right
print(17 % 10 // 2) # % and // too: (17 % 10) // 2
# The receipt: 3 coffees, 2 croissants and a 50-cent voucher split in half
total = 3 * 120 + 2 * 95 - 50 // 2
print("Total:", total)
print(True or False and False) # and before or
print(not 120 == 100) # not is applied after ==
When you run it:
19 22 -4 4 512 3 3 Total: 525 True True
Line by line:
3 + 8 * 2gives 19, not 22: first 8 × 2 = 16 and then 3 + 16. With parentheses,(3 + 8) * 2does give 22.-2 ** 2gives −4. It is the most famous trap:**has higher priority than the minus sign in front of it, so Python works out −(2²). If you want the square of −2, write(-2) ** 2, which gives 4.2 ** 3 ** 2gives 512:**is the only arithmetic operator that groups from right to left, so it is 2 ** (3 ** 2) = 2 ** 9.10 - 4 - 3gives 3: within the same level you go from left to right, (10 − 4) − 3. From right to left it would give 9.17 % 10 // 2gives 3:%and//are on the same step, so first 17 % 10 = 7 and then 7 // 2 = 3.True or False and Falsegives True:andgoes beforeor, so it isTrue or (False and False).not 120 == 100gives True:notgoes after comparisons, so it isnot (120 == 100).
And the receipt: 3 coffees, 2 croissants and a 50-cent voucher we split in half. The drawing shows how it is solved step by step and which step of the ladder each operator is on:
The sums by hand: 3 × 120 = 360; 2 × 95 = 190; 50 // 2 = 25; 360 + 190 = 550; 550 − 25 = 525. First all the * and // (from left to right) and then the addition and subtraction.
| Level (highest to lowest priority) | Operators |
|---|---|
| 1 | ( ) parentheses |
| 2 | ** (right to left) |
| 3 | -x, +x (sign) |
| 4 | * / // % |
| 5 | + - |
| 6 | == != < > <= >= |
| 7 | not |
| 8 | and |
| 9 | or |
You do not need to memorise the whole table. Knowing that ** goes before the sign, that comparisons go before not, and and or (in that order) and that when in doubt you add parentheses covers 99 % of cases. An extra pair of parentheses never breaks anything and makes code easier to read.
Common mistakes with operators
A summary of the ones we have seen, so you have them together:
Using / when you need a whole number of something (trays, tables, groups). / always gives a float; use // and, for what is left over, %.
Thinking % means “per cent”. It is the remainder of the division. A percentage is calculated with * percentage / 100.
Comparing float values with ==. Use cents, math.isclose or round.
Forgetting parentheses in averages: a + b + c / 3 only divides c. The right way is (a + b + c) / 3.
-2 ** 2 gives −4. If the negative number is the base, put it in parentheses.
Watch it step by step in Python Tutor
Python Tutor runs your code line by line and draws every variable with its value at each moment. Copy this program, choose Python 3 and press Visualize Execution:
price = 120 quantity = 3 voucher = 50 subtotal = quantity * price total = subtotal - voucher // 2 # // before - average = total / quantity # / always gives a float exact = average * quantity == total customers = 0 ok = customers != 0 and total / customers > 100 # never gets to divide name = "" customer = name or "Anonymous" # or returns a value, not a bool print(total, average, exact, ok, customer)
Output:
335 111.66666666666667 True False Anonymous
What to look at step by step:
- When
total = subtotal - voucher // 2runs,totalappears straight away with 335. Python does not store the result ofvoucher // 2in any variable: it works it out (25) before the subtraction, because of precedence, and uses it immediately. 360 − 25 = 335. averageappears as111.66666666666667: afloat, even though all the operands wereint. That is the/.exactcomes outTrue: hereaverage * quantitygives exactly 335.0 again. You will not always be that lucky with decimals; that is whymath.iscloseexists.- When you reach the
okline, notice the program moves on without an error even thoughcustomersis 0:customers != 0isFalseandandno longer evaluates the division. Swap the two parts and you will see theZeroDivisionErrorlive. customeris'Anonymous', notTrue:orreturned its second operand becausenamewas an empty text.
Summary
| Operator | What it does | Example | Result |
|---|---|---|---|
/ | True division (always float) | 5 / 2 | 2.5 |
// | Floor division (rounds down) | 17 // 5 | 3 |
% | Remainder | 17 % 5 | 2 |
** | Power | 2 ** 10 | 1024 |
==, != | Equal, not equal | 120 != 100 | True |
Chained <= | Inside a range | 0 <= 120 <= 200 | True |
and, or | Combine, with short-circuit | "" or "Anonymous" | 'Anonymous' |
not | Negate | not True | False |
+= and friends | Change a variable based on its value | till += 120 | till goes up by 120 |
math.isclose | Compare decimals with a tolerance | math.isclose(0.1 + 0.2, 0.3) | True |
Three ideas to take away:
- Every operator returns a type.
/always gives afloat,//and%give the quotient and the remainder (andb * (a // b) + a % b == a), and comparisons give abool. - Never compare decimals with
==. Work in cents when it is money and usemath.isclosewhen it is a calculation. andandorstop as soon as they know the answer and return one of their operands. Put the protecting check first and, when unsure about the order, parentheses.
With comparison and logical operators you now have everything you need for your programs to make decisions. That is exactly what comes next: in Python conditionals you will use these same expressions (grade >= 5 and attendance >= 75, divisor != 0…) inside if, elif and else. But first, put them to work in the operators practice: a unit converter, the coffee card with IGIC in cents and a calculator that does not break with negative numbers.
Did this article help you? Here is how you can support SergioLearns →




What is an operating system — theory with your laptop on a study afternoon, a write() call and a CPU that never rests (and the three programs that weren’t running at the same time)