◀ Course contents Part 1 · Module 1-06

Math & Comparisons

The operators every decision is built from

Arithmetic you mostly know already, apart from two operators that turn out to do a surprising amount of work. Comparisons and logic you may not — and every if statement, every loop condition and every filter in the rest of this track is made of them. Clear this and Part 1 is complete.

Ready?

1

Seven Arithmetic Operators, Two Worth Dwelling On

17 + 5    # 22
17 - 5    # 12
17 * 5    # 85
17 / 5    # 3.4   true division — always a float
17 // 5   # 3     floor division — the whole part
17 % 5    # 2     modulo — the remainder
17 ** 2   # 289   power

// and % are the two most people skip, and they are the two that earn their keep. Together they answer one question: how many whole ones fit, and what is left over?

Unit conversion

seconds // 60 whole minutes, seconds % 60 the leftover seconds.

Grouping

items // per_page full pages, items % per_page the last partial one.

Divisibility

n % 2 == 0 asks whether n is even. Any remainder of zero means it divides cleanly.

Cycling

index % length turns a rising counter into a repeating loop through positions.

Everyday example, splitting the bill

47 sweets between 5 children. 47 / 5 is 9.4, which is a true answer and completely useless — nobody hands out four tenths of a sweet. 47 // 5 is 9 each, and 47 % 5 is the 2 left in the bag. Those are the two numbers a person actually needs.

Quick check

You have 100 items and show 8 per page. Which expression gives the number of items on the final, partly-filled page?

2

Comparisons: Questions With Two Possible Answers

A comparison asks something about two values and hands back a bool. There are six, and they behave exactly as they look:

a == b    equal to
a != b    not equal to
a <  b    less than
a <= b    less than or equal to
a >  b    greater than
a >= b    greater than or equal to

The one that catches people is == against =. One equals sign is an instruction that changes something. Two is a question that changes nothing.

Changes something

score = 100

Assignment. Score is now 100, whatever it was before.

Asks something

score == 100

Comparison. Produces True or False and leaves score alone.

Python also lets you chain comparisons the way maths notation does, which most languages do not allow:

0 <= score <= 100      # both conditions, reads as written
low < value < high

Quick check

A pass mark is 60 and a score of exactly 60 should pass. Which comparison is right?

3

Joining Conditions Together

Three words combine conditions. Python spells them out rather than using symbols, which means a condition can be read aloud and checked against the requirement it came from.

and

Both sides must be true

signed_in and not suspended

or

At least one side must be true

is_student or is_member

not

Flips whatever follows

not suspended

Python evaluates these lazily, which is called short-circuiting. In a and b, if a is already False then nothing b could be would make the whole thing true, so b is never evaluated at all. or does the mirror image: a True on the left settles it.

Short-circuiting is a safety feature

It means the order of your conditions matters, and you can use that deliberately. Put the check that protects the risky part on the left:

if items and items[0] == "tea":

On an empty list, items is falsy, so Python stops and never touches items[0] — which would have raised an IndexError. Swap the two sides and the same line crashes.

Quick check

A member may train when they are signed in and have not been suspended. Which line says that?

4

What Python Does First

Python does not read an expression left to right. It follows a precedence order — the school rules, extended:

1.  ()              brackets
2.  **              power
3.  * / // %        multiply and divide
4.  + -             add and subtract
5.  == != < <= > >= comparisons
6.  not
7.  and
8.  or

So 2 + 3 * 4 is 14, not 20. And because comparisons come after arithmetic, total > 10 * 2 compares total against 20 rather than doubling anything. Because and beats or, the line a or b and c means a or (b and c) — which is very rarely what someone typing it quickly intended.

Brackets are free

Nobody has ever been slowed down by a pair of brackets that made an expression obvious. Plenty of people have lost an afternoon to a condition that turned out to group differently from how it read. If a line needs a moment's thought, add them — you are writing for the person who reads it next, and that person is usually you.

When in doubt, bracket it. The cost is two characters.

Quick check

What does 2 + 3 * 4 ** 2 come to?

0 of 9 completed

Real Python runs right here in your browser — nothing to install, nothing sent to a server. The interpreter downloads once the first time you press Run, then stays cached.

01

To do

Python has three division-shaped operators and they answer different questions.

17 / 5    →  3.4   true division, always a float
17 // 5 → 3 floor division, the whole part
17 % 5 → 2 modulo, the remainder

// and % are a pair: together they answer "how many whole ones fit, and what is left over?". That single idea handles splitting things into groups, converting units, and checking whether a number divides evenly.

Your task: 47 sweets are shared between 5 children. Work out each (how many each child gets), left_over (how many remain), and exact (the true division result). Print all three, one per line.

your_code.py
Python
Hint

// gives the whole number of sweets each child gets, % gives what is left in the bag, and / gives the fractional answer nobody can actually hand out.

Output

      
    02

    To do

    % looks like a school-maths curiosity and turns out to be one of the most reached-for operators there is. Two patterns cover nearly every use:

    1

    Does it divide evenly?

    n % 2 == 0 is "is it even". n % 10 == 0 is "is it a round ten" — the check behind "every tenth request, log a sample".

    2

    Wrapping round a cycle

    Days of the week, hours on a clock, positions on a board. (start + steps) % 7 lands you on the right day however far you count.

    Your task: a session ran for 5205 seconds. Work out is_even (does that number divide by 2 exactly) and every_tenth (does it divide by 10 exactly). Then, starting on day 2 of the week and counting forward 100 days, work out landing_day. Print all three.

    False
    False
    4
    your_code.py
    Python
    Hint

    "Divides evenly" means the remainder is zero: total_seconds % 2 == 0. For the day, add the two numbers first and then take the remainder — bracket the addition so it happens before the %.

    Output
    
          
      03

      To do

      Two rules here are worth knowing before they cost you an afternoon.

      // floors, it does not truncate. For positive numbers those look the same. For negative ones they do not: -7 // 2 is -4, because it rounds down to the next whole number, while int(-7 / 2) is -3, because int() chops toward zero.

      round() goes to the nearest even number on a tie. round(2.5) is 2 and round(3.5) is 4. This is not a bug — always rounding halves up would bias a long column of figures upward, and every accounting standard that cares specifies exactly this.

      Your task: print these four values, in this order: -7 // 2, int(-7 / 2), round(2.5), round(3.5).

      -4
      -3
      2
      4
      your_code.py
      Python
      Hint

      print(-7 // 2), then print(int(-7 / 2)), then the two round() calls. Writing the expression rather than the answer is the point.

      Output
      
            
        04

        To do

        A comparison asks a question and hands back a bool. There are six of them:

        a == b   equal to        a != b   not equal to
        a < b less than a <= b less than or equal
        a > b greater than a >= b greater than or equal

        The one to watch is == against =. A single equals sign assigns — it changes something. A double equals sign asks — it changes nothing and produces True or False.

        Python also lets you chain comparisons the way maths does: 0 <= score <= 100 means both at once, and reads exactly as it looks.

        Your task: with score at 72 and pass_mark at 60, work out passed (is the score at least the pass mark?), perfect (is it exactly 100?), and in_range (is it between 0 and 100 inclusive, written as one chained comparison). Print all three.

        your_code.py
        Python
        Hint

        "At least" means >=, not >. For in_range, write it as one chain: 0 <= score <= 100.

        Output
        
              
          05

          To do

          Three comparisons that catch people, all for good reasons.

          0.1 + 0.2 == 0.3 is False. Floats are stored in binary and the sum lands a hair above 0.3. Never compare two floats for exact equality — round both to the precision you actually care about, or check the difference is small.

          "5" == 5 is False. Python will not quietly convert one to the other, which is the whole reason the type bugs in the last module were findable at all.

          5 == 5.0 is True. An int and a float are different types but the same number, and == compares value.

          Your task: print those three, plus the rounded version, in this order:

          False
          True
          False
          True

          Line 1 is 0.1 + 0.2 == 0.3. Line 2 is the same comparison with both sides rounded to two decimal places. Line 3 is "5" == 5. Line 4 is 5 == 5.0.

          your_code.py
          Python
          Hint

          For line 2: round(0.1 + 0.2, 2) == 0.3. The rounding has to happen before the comparison, so it goes inside its own brackets.

          Output
          
                
            06

            To do

            Three words join conditions together. and needs both sides true. or needs at least one. not flips whatever follows it.

            True  and False   →  False
            True or False → True
            not True → False

            Python is lazy about these, in a useful way. In a and b, if a is already False there is no way the whole thing can be true, so b is never evaluated at all. That is called short-circuiting, and it is what lets you write a safety check first and the risky part second.

            Your task: a member can train when they are signed in and have not been suspended. They get a discount when they are either a student or a member. Work out can_train and gets_discount from the four flags given, and print both.

            your_code.py
            Python
            Hint

            "Has not been suspended" is `not suspended`. Join it to signed_in with `and`. The discount is is_student or is_member.

            Output
            
                  
              07

              To do

              and stops as soon as it knows the answer. If the left side is already False, nothing can rescue the whole expression, so the right side is never evaluated at all. Same for or when the left side is already True.

              That is not a performance trick. It is what lets a condition protect itself: put the check that makes the rest safe on the left, and the risky part on the right.

              count != 0 and total / count > 100   # safe
              total / count > 100 and count != 0 # crashes when count is 0

              Your task: the code below divides before it checks. Run it, read the error, then reorder the condition so it prints False without crashing. Do not change the two values.

              your_code.py
              Python
              Hint

              Swap the two halves. count != 0 goes first, and because it is False, Python never reaches the division at all.

              Output
              
                    
                08

                To do

                Python does not read left to right. It follows the same precedence rules you learned in school, extended a little:

                1. ()          brackets
                2. ** power
                3. * / // % multiply and divide
                4. + - add and subtract
                5. == != < > comparisons
                6. not, and, or

                So 2 + 3 * 4 is 14, not 20. And because comparisons happen after arithmetic, total > 10 * 2 compares against 20 rather than doubling the answer.

                Brackets beat all of it, and cost nothing. When a line needs a moment's thought to read, add them.

                Your task: the same four numbers, three different answers. Set plain to the value of 2 + 3 * 4 ** 2 exactly as written, bracketed to the value of that expression with brackets forcing strict left-to-right order, and average to the mean of 4, 8 and 12. Print all three.

                your_code.py
                Python
                Hint

                Power first, then multiply, then add: 3 * 4 ** 2 is 3 * 16. For strict left to right, bracket every step: ((2 + 3) * 4) ** 2. For the average, remember to bracket the sum before dividing.

                Output
                
                      
                  09

                  To do

                  Both of these ran in production somewhere. Neither raised an error. Both produced a number or a decision that was quietly wrong, which is the expensive kind.

                  The average. 4 + 8 + 12 / 3 divides only the last number, so it reports 16.0 where the mean is 8.0.

                  The permission check. and binds tighter than or, so user == "admin" or user == "root" and active reads as user == "admin" or (user == "root" and active) — which lets an inactive admin through. The intent was (admin or root) and active.

                  Your task: fix both with brackets, so the output is:

                  8.0
                  False

                  Keep the same values and the same comparisons — add brackets, nothing else.

                  your_code.py
                  Python
                  Hint

                  Bracket the whole sum before dividing it. And bracket the two name checks together, so the `and active` applies to both rather than only to the second one.

                  Output
                  
                        

                    Break a session time down

                    To do

                    A training session lasted total_seconds. Turn that single number into hours, minutes and seconds, and report on it.

                    Work out these variables from total_seconds alone:

                    • hours — whole hours in the total
                    • minutes — whole minutes left after the hours are taken out
                    • seconds — seconds left after that
                    • is_long — True when the session ran an hour or more
                    • exact_minutes — the total as a decimal number of minutes
                    • whole_minutes — True only when the total divides into whole minutes with nothing left over

                    Then print exactly four lines:

                    1h 26m 45s
                    Exact minutes: 86.75
                    Long session: True
                    Whole minutes: False

                    The second line shows two decimal places, and every figure has to be calculated from total_seconds — this one number is an example, not the specification.

                    your_code.py
                    Python
                    Hint

                    // and % in turn: hours is total_seconds // 3600, and total_seconds % 3600 is what remains, which you then split the same way with // 60 and % 60. is_long and whole_minutes are both comparisons, so neither needs an if statement — and "nothing left over" means the remainder equals 0.

                    Output
                    
                          

                      Notification