Python loops — exercises with FizzBuzz, a growing investment, primes and a savings plan (and the break that only left the tray)

In an FP1 mock exam I got a search exercise: “go through the trays on the counter and say where the first chocolate croissant is”. Two loops, one inside the other, and a break when it’s found. I handed it in without a worry. When it was marked, my program had found two “first” croissants. The break worked, yes… but it only got me out of the tray loop; the outer one happily moved on to the next tray. You’ll find it in “What’s wrong here?”, with the fix and a diagram of which pieces each version checks.

You already have the theory and the practice of Python loops. Now it’s your turn: four exercises on three levels (basic, intermediate and final challenge), three snippets with a hidden bug, solutions commented line by line and a cheat sheet to keep everything at hand. All the programs use fixed data, no input(), and the outputs you see come from their real run.

How to use this article

  1. Read the statement and the expected output, and write your solution in VS Code without looking at anything else.
  2. If you’ve been stuck for more than 10 minutes, open the hint (and only the hint).
  3. Compare your output with the expected one character by character: one number too many or too few is usually a badly closed range.
  4. Read the commented solution even if yours worked: there’s often a decision you hadn’t thought of.

Basic level

Exercise 1: FizzBuzz

FizzBuzz is probably the most famous programming exercise in the world; it’s even used as a filter in job interviews. Write a program that goes through the numbers 1 to 100 and, for each one:

  • if it’s divisible by 3 and by 5, writes FizzBuzz;
  • if it’s only divisible by 3, Fizz;
  • if it’s only divisible by 5, Buzz;
  • otherwise, the number itself.

So the output doesn’t take 100 lines, write the results separated by spaces and break the line every 10 numbers. Expected output:

1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 
11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz 
Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 
31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 
41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz 
Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 
61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 
71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz 
Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 
91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz 

for i in range(1, 101): you know there are 100 numbers (and the stop is left out). The trick is the order of the if/elif: the “divisible by 3 and by 5” case has to come first. To avoid a line break after every number, print(text, end=" "); to break every 10, an if i % 10 == 0: print().

Exercise 2: Compound interest calculator

The café tip jar has collected 1,000 €, which goes into an account at 5 % a year for 5 years. With compound interest, each year’s interest is added to the capital and earns interest itself the following year: capital = capital × (1 + interest / 100). Write a program that shows the capital at the end of each year (rounded to 2 decimals) with what was earned that year, and at the end the capital, the total earned and the return as a percentage. Expected output:

--- Investment growth ---
Year 1: 1050.00 € (+50.00 €)
Year 2: 1102.50 € (+52.50 €)
Year 3: 1157.62 € (+55.12 €)
Year 4: 1215.50 € (+57.88 €)
Year 5: 1276.28 € (+60.78 €)
Final capital: 1276.28 €
Total earned: 276.28 €
Return: 27.63 %

for year in range(1, years + 1), because you know how many years there are. For each year’s gain you need the capital from before it’s updated: save it in another variable at the start of the pass. Round with round(…, 2) every year, as a bank would.

Intermediate level

Exercise 3: Prime number finder

A number is prime if it’s only divisible by 1 and itself. Write a program that finds all the primes from 2 to 30, shows them on one line, says how many there are and counts how many divisions (%) it had to do in total. Expected output:

Primes up to 30: 2 3 5 7 11 13 17 19 23 29 
Total: 10 primes
Divisions done: 45

Two nested loops. The outer one goes through the candidates from 2 to 30; the inner one tries divisors. Use a flag is_prime = True that becomes False if you find a divisor, and a break at that moment (no need to keep going with that number). It’s enough to try divisors up to the square root: range(2, int(number ** 0.5) + 1). If you get more than 45 divisions, you’re missing the break or the square-root limit.

Final challenge

Exercise 4: Monthly savings simulator

The café wants a new 10,000 € coffee machine. Every month 300 € is saved into an account at 4 % a year. Each month, the 300 € goes in first and then the monthly interest is applied (the annual rate divided by 12), rounding the balance to 2 decimals. How many months will it take to reach the goal? Show the balance from the third year on (month 25 onwards) up to the month the goal is reached, the time in years and months, the amount saved, the amount paid in and the interest. And if the monthly saving were 0 or negative, the program must warn you instead of hanging. Expected output:

Month 25: 7833.84 €
Month 26: 8160.95 €
Month 27: 8489.15 €
Month 28: 8818.45 €
Month 29: 9148.84 €
Month 30: 9480.34 €
Month 31: 9812.94 €
Month 32: 10146.65 €
Goal reached in 32 months (2 years and 8 months)
Saved: 10146.65 € | paid in: 9600.00 €
Interest: 546.65 €

You don’t know how many months it will take, so while balance < goal:. The monthly interest is 4 / 12 / 100. For years and leftover months, months // 12 and months % 12 (you saw them in operators). And think about what would happen with monthly_saving = 0: the balance would never grow and the while would never end, so check it with an if before the loop.

What’s wrong here?

Three short snippets, each with a typical loop bug. Before reading the explanation, predict what they print.

Snippet 1: the days that don’t add up

We want to add up the sales of days 1 to 10, at 100 € a day:

# I want to add up the sales of days 1 to 10 (100 € a day)
total = 0
for day in range(1, 10):
    total += 100
print("Last day added:", day)
print("Total:", total, "€")

What does it print? Think before reading on.

Real output:

Last day added: 9
Total: 900 €

100 € is missing: day 10 was never added. range(1, 10) produces 1 to 9, because the stop is never included. That’s why day ends at 9 and the total is 9 × 100 = 900.

The off-by-one error. If you want to reach N, the range stop is N + 1.

The fix is changing the 10 to 11:

# Fixed: range's stop is left out, so to reach 10 you write 11
total = 0
for day in range(1, 11):
    total += 100
print("Last day added:", day)
print("Total:", total, "€")

Output:

Last day added: 10
Total: 1000 €

To check a range without running the whole loop, print list(range(1, 10)) or len(range(1, 10)). If len doesn’t give the days you expect, that’s where the bug is.

Snippet 2: the first chocolate croissant

This is the one from my story. The trays are texts: each letter is a piece (P plain, C chocolate). We want the first chocolate croissant and then stop:

# I look for the FIRST chocolate croissant (C) and want to stop as soon as I find it
trays = ["PPC", "CPC", "PPP"]  # P = plain, C = chocolate
num = 0
for tray in trays:
    num += 1
    slot = 0
    for piece in tray:         # a for also walks through a text, letter by letter
        slot += 1
        if piece == "C":
            print(f"Chocolate: tray {num}, slot {slot}")
            break
print("Search finished")

How many “Chocolate” lines will come out?

Real output:

Chocolate: tray 1, slot 3
Chocolate: tray 2, slot 1
Search finished

Two. The break gets out of the pieces loop (for piece in tray), but not out of the trays loop: the outer one makes its next pass, goes into tray 2 and finds another chocolate. break only ends the innermost loop it’s in. The diagram compares which pieces each version gets to check:

Which pieces each version checksTwo panels with three trays of three pieces (C = chocolate, P = plain). With only break, it checks the three pieces of tray 1, the first one of tray 2 and the three of tray 3, finding two chocolates. With the flag, only tray 1 is checked.Only breaktray 1PPCbreaktray 2CbreakPCtray 3PPP2 chocolates: the outer loop goes onbreak + flagtray 1PPCbreaktray 2CPCnot checkedtray 3PPPnot checked1 chocolate: the flag stops the outer one
break only leaves the loop it is in; to stop the outer one too you need another signal.

Expecting a break inside two loops to end both. It only ends the inner one.

The fix: a flag that the inner loop sets to True and the outer loop checks after each tray:

# Fixed: a flag tells the outer loop that we are done
trays = ["PPC", "CPC", "PPP"]  # P = plain, C = chocolate
num = 0
found = False
for tray in trays:
    num += 1
    slot = 0
    for piece in tray:
        slot += 1
        if piece == "C":
            print(f"Chocolate: tray {num}, slot {slot}")
            found = True
            break              # leaves the pieces loop...
    if found:
        break                  # ...and this one, the trays loop
print("Search finished")

Output:

Chocolate: tray 1, slot 3
Search finished

Once you know functions (the next topic), there’s an even cleaner way: put the search inside a function and use return, which leaves all the loops at once.

Snippet 3: the total that forgets

Adding up the morning tickets:

# Add up the morning tickets
tickets = [3.50, 1.20, 4.80]
for ticket in tickets:
    total = 0
    total += ticket
print(f"Total: {total:.2f} €")

What’s the total?

Real output:

Total: 4.80 €

4.80 €: only the last ticket. total = 0 is inside the loop, so it resets on every pass before adding. At the end of pass 3, total is 0 + 4.80. What was added on passes 1 and 2 is lost.

Initialising the accumulator inside the loop. It goes before, level with the for.

# Fixed: the accumulator is created ONCE, before the loop
tickets = [3.50, 1.20, 4.80]
total = 0
for ticket in tickets:
    total += ticket
print(f"Total: {total:.2f} €")

Output:

Total: 9.50 €

Check: 3.50 + 1.20 + 4.80 = 9.50 €.

Commented solutions

Solution to exercise 1: FizzBuzz

# Basic level · Exercise 1: FizzBuzz from 1 to 100, ten per line
for i in range(1, 101):          # 101 so that 100 is included
    if i % 3 == 0 and i % 5 == 0: # the double case FIRST: otherwise 15 would stay as "Fizz"
        text = "FizzBuzz"
    elif i % 3 == 0:
        text = "Fizz"
    elif i % 5 == 0:
        text = "Buzz"
    else:
        text = str(i)            # the number as it is, as text
    print(text, end=" ")         # everything on the same line...
    if i % 10 == 0:
        print()                  # ...until we reach a multiple of 10

Why it’s done this way:

  • The order of the conditions. 15 is divisible by 3 and by 5. If the first question were i % 3 == 0, 15 would go in there, write “Fizz” and the elifs below wouldn’t even be looked at. That’s why the double case comes first. Another equivalent way: i % 15 == 0 (divisible by 3 and by 5 is the same as divisible by 15).
  • One text variable and a single print. Each branch only decides which text it is; the print appears once, at the end. If you change the format tomorrow, you change it in one place.
  • str(i). In the other branches text is a text; this way all four branches leave the same type in the variable.
  • The line break. end=" " keeps everything on the same line, and if i % 10 == 0: print() breaks at 10, 20… The empty print() only prints the line break.

Checking the first line: 3, 6 and 9 → Fizz; 5 and 10 → Buzz; the rest, numbers. On the second line, 15 → FizzBuzz.

Solution to exercise 2: Compound interest

# Basic level · Exercise 2: compound interest year by year
initial_capital = 1000.0
interest = 5.0                      # % per year
years = 5

capital = initial_capital           # the capital that keeps growing (the initial one is not touched)
print("--- Investment growth ---")
for year in range(1, years + 1):    # we know how many years: for
    previous = capital              # saved BEFORE updating, for the year's gain
    capital = round(capital * (1 + interest / 100), 2)
    gain = round(capital - previous, 2)
    print(f"Year {year}: {capital:.2f} € (+{gain:.2f} €)")

total = round(capital - initial_capital, 2)
print(f"Final capital: {capital:.2f} €")
print(f"Total earned: {total:.2f} €")
print(f"Return: {total / initial_capital * 100:.2f} %")

Why it’s done this way:

  • for, not while: we know there are 5 years.
  • capital and initial_capital kept apart: capital keeps changing, but at the end we need the initial one to work out what was earned and the return.
  • previous is saved at the start of the pass: after capital = … the old value no longer exists. Without previous, we couldn’t know what was earned that year.
  • round(…, 2) every year, as a bank would: the next year is computed on the already-rounded capital.

Pass-by-pass trace:

Yearpreviouscapital × 1.05capital (rounded)gain
11000.001050.01050.0050.00
21050.001102.51102.5052.50
31102.501157.6251157.6255.12
41157.621215.5011215.5057.88
51215.501276.2751276.2860.78

Why does year 3 round to 1157.62 and not 1157.63? Because 1157.625 can’t be stored exactly in a float: in memory it’s something like 1157.62499999…, and round rounds it down. It’s the same float issue we saw in variables and data types. The return: 276.28 / 1000 × 100 = 27.63 %.

If you need exact cents (as with the till change in the theory), work in whole cents and divide by 100 only when displaying.

Solution to exercise 3: Prime numbers

# Intermediate level · Exercise 3: prime numbers up to n
n = 30
primes = []
checks = 0                        # how many divisions it does in total

for number in range(2, n + 1):    # outer loop: each candidate
    is_prime = True               # innocent until proven otherwise
    for divisor in range(2, int(number ** 0.5) + 1):   # going up to the root is enough
        checks += 1
        if number % divisor == 0:
            is_prime = False
            break                 # there is a divisor: no need to go on with THIS number
    if is_prime:
        primes.append(number)

text = ""
for p in primes:
    text += str(p) + " "
print(f"Primes up to {n}: {text}")
print(f"Total: {len(primes)} primes")
print(f"Divisions done: {checks}")

Why it’s done this way:

  • The is_prime flag is set to True at the start of each outer pass. Every candidate starts out “innocent”. If you set it before the outer loop, as soon as one number wasn’t prime (4), all the others would be marked as not prime.
  • The break cuts the divisors loop as soon as one shows up: 30 is known not to be prime after dividing by 2, no need to try 3, 4 and 5. That’s why there are 45 divisions and not many more.
  • Up to the square root: if a number has a divisor greater than its root, it also has a smaller one (for example, 28 = 2 × 14), and we’d already have found that one. int(number ** 0.5) + 1 is the usual range + 1.
  • For 2 and 3, the inner loop is empty (range(2, 2)): it makes no passes, the flag stays True and they’re counted as primes, which is correct.

This is where break acts for each number:

Primes up to 30 and where break actsThe numbers from 2 to 30 in three rows. The primes 2, 3, 5, 7, 11, 13, 17, 19, 23 and 29 are violet. Each composite number shows its first divisor, which is where the inner loop breaks.From 2 to 30: violet = prime · “÷d” = first divisor, where break kicks in234÷256÷278÷29÷310÷21112÷21314÷215÷316÷21718÷21920÷221÷322÷22324÷225÷526÷227÷328÷22930÷2
For each composite number, the inner loop stops as soon as it finds its first divisor.

Zooming into the two loops:

for number in range(2, n + 1):    # outer loop: each candidate
    is_prime = True               # innocent until proven otherwise
    for divisor in range(2, int(number ** 0.5) + 1):   # going up to the root is enough
        checks += 1
        if number % divisor == 0:
            is_prime = False
            break                 # there is a divisor: no need to go on with THIS number
    if is_prime:
        primes.append(number)
numberdivisors triedbreak?is_prime
2, 3none (empty range)—True
42yes, at 2False
92, 3yes, at 3False
252, 3, 4, 5yes, at 5False
292, 3, 4, 5noTrue

Solution to exercise 4: Savings simulator

# Final challenge · Exercise 4: how many months to reach the goal?
goal = 10000.0
monthly_saving = 300.0
annual_interest = 4.0         # %

if monthly_saving <= 0:       # with 0 € a month the while would never end
    print("Error: monthly savings must be greater than 0")
else:
    monthly_interest = annual_interest / 12 / 100
    balance = 0.0
    month = 0
    paid_in = 0.0
    while balance < goal:     # we don't know how many months: while
        month += 1
        balance += monthly_saving                          # 1st the month is paid in
        balance = round(balance * (1 + monthly_interest), 2) # 2nd interest is applied
        paid_in += monthly_saving
        if month > 24:        # we only show the last months
            print(f"Month {month}: {balance:.2f} €")

    years = month // 12
    remainder = month % 12
    print(f"Goal reached in {month} months ({years} years and {remainder} months)")
    print(f"Saved: {balance:.2f} € | paid in: {paid_in:.2f} €")
    print(f"Interest: {balance - paid_in:.2f} €")

Why it’s done this way:

  • The if before the while: with monthly_saving <= 0 the balance would never grow and balance < goal would be True forever. It’s checked before going in, not inside.
  • while, not for: we don’t know how many months it takes; that’s precisely what we want to find out.
  • The order inside the pass: first the money goes in, then the interest is applied, as the statement says. The other way round you’d get a different number of months (that month’s 300 € wouldn’t earn interest that month).
  • month starts at 0 and is added at the start of the pass: so when the loop ends, month is exactly the number of months simulated.
  • if month > 24 inside the loop: decides which months are printed without having to store the history.

Zooming into the loop:

while balance < goal:     # we don't know how many months: while
    month += 1
    balance += monthly_saving                          # 1st the month is paid in
    balance = round(balance * (1 + monthly_interest), 2) # 2nd interest is applied
    paid_in += monthly_saving
    if month > 24:        # we only show the last months
        print(f"Month {month}: {balance:.2f} €")

Check: 32 months are 32 // 12 = 2 years and 32 % 12 = 8 months. Paid in: 32 × 300 = 9,600 €. Interest: 10,146.65 − 9,600 = 546.65 €. In month 31 the balance (9,812.94 €) still hasn’t reached 10,000, so the loop makes one more pass; in month 32 it goes over and the condition 10146.65 < 10000.0 is now False.


Exam-style quiz

Now test yourself as in the exam. The FP1 quizzes look like this: 15 questions in 20 minutes (16 in 30 in the Sequences one), almost all single choice (each wrong answer subtracts a third of what the question is worth) and many «what does this code print?», with the odd fill in the gaps, matching or true or false. Here are 13 original questions on loops. Answer without running anything, press Check and read the explanation for each one. These questions are also the question bank for the FP1 theory mock exam, which will mix them with those from the other topics.

Question 1Short answer

What is the value of x at the end? Write only the number.

x = 0
i = 1
while i < 5:
    x += i
    i += 1
print(x)
Solution

Answer: 10

The loop adds i while i < 5: 1 + 2 + 3 + 4 = 10. When i reaches 5, the condition is false and the loop ends without adding it.

Question 2Single choice

Which numbers does range(2, 10, 3) produce?

  1. 2, 5 and 8
  2. 2, 5, 8 and 11
  3. 2, 3, 4, 5, 6, 7, 8 and 9
  4. 3, 6 and 9
Solution

Answer: 2, 5 and 8

range(start, stop, step): it starts at start, adds step each time and does not include stop. That is why range(5) gives 0, 1, 2, 3 and 4.

Question 3Short answer

How many times is hello printed? Write only the number.

for i in range(3):
    for j in range(4):
        print("hello")
Solution

Answer: 12

For each of the 3 turns of the outer loop, the inner one does 4 turns: 3 × 4 = 12. In nested loops, the turns multiply.

Question 4Single choice

What does this code print?

for n in range(1, 10):
    if n % 4 == 0:
        break
    print(n, end=" ")
  1. 1 2 3
  2. 1 2 3 4
  3. 1 2 3 5 6 7 9
  4. 4 8
Solution

Answer: 1 2 3

break ends the whole loop as soon as it runs. continue, on the other hand, skips the rest of that turn and carries on with the next one.

Question 5Short answer

What does this program print? Write the exact output.

s = 0
for n in range(1, 8):
    if n % 2 == 0:
        continue
    s += n
print(s)
Solution

Answer: 16

continue skips the even numbers, so only the odd ones from 1 to 7 are added: 1 + 3 + 5 + 7 = 16.

Question 6Single choice

When is a while better than a for?

  1. When you do not know in advance how many turns the loop will take
  2. When you want to go through a list
  3. Never: while is an old form of for
  4. When the loop has a fixed number of turns
Solution

Answer: When you do not know in advance how many turns the loop will take

for = «do this for each element» (or a fixed number of times). while = «repeat while the condition holds». With while, remember to change something inside the loop or it will never end.

Question 7Single choice

What is wrong with this program?

i = 10
while i > 0:
    print(i)
i -= 1
  1. It never ends: i -= 1 is outside the loop and i is always 10
  2. It prints 10 down to 1
  3. It only prints 10
  4. It is a syntax error
Solution

Answer: It never ends: i -= 1 is outside the loop and i is always 10

It is an infinite loop: the condition i > 0 never stops holding because i does not change inside the loop. In the terminal you stop it with Ctrl + C.

Question 8True or false

True or false?

  1. for letter in 'code': does 4 turns.
  2. range(5) includes 5.
  3. A while whose condition is false from the start does not do any turn.
  4. break inside two nested loops leaves both.
Solution
  • T — for letter in 'code': does 4 turns.
  • F — range(5) includes 5.
  • T — A while whose condition is false from the start does not do any turn.
  • F — break inside two nested loops leaves both.

A for goes through any sequence, text included (one turn per character). range(5) goes from 0 to 4. And break only leaves the loop it is in: the outer one carries on.

Question 9Single choice

What does this code print?

n = 1
while n < 100:
    n = n * 3
print(n)
  1. 243
  2. 81
  3. 99
  4. 100
Solution

Answer: 243

The while checks the condition before each turn. With n = 81, 81 < 100 is true and it goes in: n = 243. Then 243 < 100 is false and it leaves. The final value can go past the limit.

Question 10Fill in the gaps

Complete the loop so that it adds the numbers from 1 to 10 (both included):

total = 0 and then for i in range(1, ____): with total ____ i inside.

Words:

  • =
  • +=
  • 11
  • 10
  • -=
Solution

total = 0 and then for i in range(1, 11): with total += i inside.

Since the end of range is not included, to reach 10 you must write 11. And total += i accumulates; with total = i you would only keep the last one.

Question 11Single choice

What does this code print?

count = 0
for c in "Gran Canaria":
    if c == "a":
        count += 1
print(count)
  1. 4
  2. 5
  3. 3
  4. 2
Solution

Answer: 4

It is the counter pattern: start at 0 and add 1 every time the condition holds. Since 'a' == 'A' is false, capitals would not count.

Question 12Short answer

What does this program print? Write the exact output.

biggest = 0
for n in [4, 17, 9, 23, 8]:
    if n > biggest:
        biggest = n
print(biggest)
Solution

Answer: 23

It is the maximum pattern: you keep the best seen so far and change it when a bigger one appears. 4 → 17 → (9 no) → 23 → (8 no): 23 remains.

Question 13Single choice

What does the else of this loop do?

for n in [3, 7, 11]:
    if n % 2 == 0:
        print("found an even one")
        break
else:
    print("none is even")
  1. It runs because the loop finished without going through the break
  2. It runs on every turn in which the if is false
  3. It is an error: a for cannot have an else
  4. It never runs
Solution

Answer: It runs because the loop finished without going through the break

The else of a for (or a while) runs when the loop ends normally, without break. It is great for searches: «if I have not found it…».

Watch it step by step in Python Tutor

On pythontutor.com, with Python 3, you can watch snippet 2’s bug live. Paste this short version:

# For Python Tutor: the break that only leaves the inner loop
trays = ["PPC", "CPC", "PPP"]
num = 0
for tray in trays:
    num += 1
    slot = 0
    for piece in tray:
        slot += 1
        if piece == "C":
            print(num, slot)
            break
print("end")

Output:

1 3
2 1
end

What to watch step by step:

  1. In the first tray, piece takes “P”, “P” and “C”: a for over a text goes through its letters.
  2. When piece is “C”, 1 3 is printed and the arrow jumps from the break to the outer for tray line, not to print("end").
  3. num becomes 2 and slot goes back to 0: the outer loop carries on as if nothing happened.
  4. In tray 2 the chocolate is in the first slot: a second print (2 1) and a second break.
  5. Tray 3 is walked through completely (no “C”) and finally end is printed. Now try the flag version and watch the arrow leave both loops.

Cheat sheet: Python loops

The essentials in 30 seconds: for when you know how many passes there will be (it walks a sequence or a range); while when you don’t (it repeats while the condition is True, and something inside has to make it false). range never includes the stop. break leaves the loop (only the innermost); continue skips to the next item. Accumulators are prepared before the loop.

I want to…CodeResult
Walk through a listfor t in [3.5, 1.2]: print(t)3.5 and 1.2
Repeat N timesfor i in range(3): print(i)0, 1, 2
From 1 to 10range(1, 11)1 … 10
Count downrange(5, 0, -1)5, 4, 3, 2, 1
In twosrange(0, 11, 2)0, 2, 4, 6, 8, 10
Repeat while something holdswhile queue > 0: queue -= 2stops when queue ≤ 0
Leave when something is foundif t > 5: breakends the loop
Skip one caseif t == 0: continuegoes to the next one
“Do while”while True: … if ok: breakat least one pass
Print on the same lineprint(x, end=" ")no line break
PatternBefore the loopInside the loop
Sumtotal = 0total += x
Countern = 0if cond: n += 1
Productp = 1p *= x
Maximumhighest = items[0]if x > highest: highest = x
Texttext = ""text += str(x) + " "
Search in two loopsfound = Falsefound = True, break and, outside, if found: break

Exercise templates:

  • FizzBuzz: for i in range(1, 101): + if i % 3 == 0 and i % 5 == 0: first → 10 lines of 10.
  • Compound interest: previous = capital → capital = round(capital * (1 + interest / 100), 2) → 1276.28 € in 5 years.
  • Primes: an is_prime = True flag per candidate + for divisor in range(2, int(n ** 0.5) + 1) + break → 10 primes up to 30, 45 divisions.
  • Savings: if saving <= 0 first + while balance < goal: + month // 12 and month % 12 → 32 months.
SymptomLikely cause
The program never endswhile that doesn’t update the variable, or continue before the update
The last number is missingrange(1, n) instead of range(1, n + 1)
The loop does nothing and there’s no errorEmpty range: range(5, 0) without -1, or a while condition false from the start
The total is only the last valueAccumulator initialised inside the loop
It finds “the first one” several timesbreak inside two loops: it only leaves the inner one
Everything is 0 when multiplyingProduct accumulator starting at 0
NameError with the accumulatorIt wasn’t initialised before the loop
IndexError in a while over a listThe condition lets one pass too many through (<= instead of <, or or instead of and)

Before handing it in, ask yourself:

  1. Do I know how many passes each loop makes? Did I choose for or while because of that?
  2. In each while, which line moves the condition towards False, and does it run on every pass?
  3. Do my ranges reach exactly where I want (the stop is left out)?
  4. Are my accumulators initialised before the loop with the right value (0, 1 or "")?

If you still have doubts, go back to the loops theory or review the practice. And if you’ve got it, the next topic is Python functions: what we repeat with loops today, we’ll store under its own name tomorrow.

Keep goingAll Python articles

Did this article help you? Here is how you can support SergioLearns →

Sigue aprendiendo

Leave a Reply

Your email address will not be published. Required fields are marked *