Loops

💡 Big Idea

A loop is a way of making a computer repeat an action — without writing that action out over and over again. Loops are one of the most powerful ideas in programming: they let a program process ten items or ten million items with the same few lines of code. Python has two kinds of loop, each suited to a different situation: the <strong>while</strong> loop repeats as long as a condition is true, and the <strong>for</strong> loop steps through a collection one item at a time.

1   Why Do We Need Loops?

Suppose you want to print a countdown from 5 to 1. You could write it out by hand:

print(5)
print(4)
print(3)
print(2)
print(1)
print("Liftoff!")

That works for five numbers. But what if you needed a countdown from 1,000? Or if you had a list of 500 student names to process? Writing one line per item is not programming — it is just typing. Loops solve this.

🔍 Analogy: A Shampoo Bottle

The instructions on a shampoo bottle say: "Lather, rinse, repeat." They do not say: "Lather, rinse. Now lather again, rinse again. Now lather a third time..." A loop is the "repeat" instruction. You describe the action once, and the computer carries it out as many times as needed.

Here is the same countdown written with a loop — it will work whether the starting number is 5 or 5,000:

n = 5
while n > 0:
    print(n)
    n -= 1
print("Liftoff!")

2   The while Loop

A while loop keeps running its body as long as a condition is True. Every time Python reaches the bottom of the loop body, it jumps back to the top and checks the condition again. When the condition becomes False, the loop stops and Python moves on to whatever comes next.

2.1   The Structure

while condition:
    # body: runs repeatedly as long as condition is True

The rules are the same as for if statements: a colon after the condition, and the body indented. The critical difference is that an if runs its body at most once. A while loop can run its body thousands of times.

🔍 Analogy: A Vending Machine

A vending machine keeps accepting coins while the balance is less than the item price. Each coin inserted increases the balance, and the machine checks again. The moment the balance reaches the price, the loop ends and the item is dispensed. Something inside the loop (inserting a coin) changes the state so that the condition eventually becomes false. That change is essential — without it, the loop runs forever.

2.2   A Full Example with Trace

count = 1

while count <= 4:
    print("Count is:", count)
    count += 1

print("Done.")

Let's trace this execution step by step — this is called a loop trace. Good programmers do this on paper before running unfamiliar loops:

Iterationcount (at top)Condition: count <= 4Loop runs?Printedcount (at bottom)
111 <= 4 → TrueYesCount is: 12
222 <= 4 → TrueYesCount is: 23
333 <= 4 → TrueYesCount is: 34
444 <= 4 → TrueYesCount is: 45
55 <= 4 → FalseNo — exit loop

After the loop exits, Python prints "Done." — that line is outside the loop (not indented under while), so it runs exactly once.

2.3   The Infinite Loop — and How to Avoid It

The most dangerous mistake with a while loop is writing one where the condition never becomes False. This is called an infinite loop — the program runs forever and never moves on:

# DANGER: infinite loop — count never changes, condition never becomes False
count = 1
while count <= 4:
    print("Count is:", count)
    # forgot count += 1 !

Every while loop needs something inside it that changes the state so the condition can eventually become False. Before you write a while loop, always ask: "What will make this condition false, and does my loop actually do that?"

⚠️ If your program freezes — you are probably in an infinite loop

If you run a program and it just sits there producing output endlessly (or nothing at all), press Ctrl + C in the terminal to interrupt it. Then look for the while loop that has no way out. The fix is almost always a missing update to the variable that the condition checks.

2.4   A Practical while Loop: Input Validation

One of the most common real uses of a while loop is asking the user for input repeatedly until they give a valid answer. This is called an input validation loop:

age = int(input("Enter your age: "))

while age < 0 or age > 120:
    print("That does not look like a valid age. Please try again.")
    age = int(input("Enter your age: "))

print("Thank you! Age recorded:", age)

The loop keeps running as long as the input is invalid. The moment a valid age is entered, the condition becomes False and the loop exits cleanly. This pattern — keep asking until the answer is acceptable — is something you will use constantly.

✅ Check Your Understanding
  1. What is the key difference between a while loop and an if statement — even though they both use a condition?
  2. Trace this loop on paper. Fill in the value of x at the start of each iteration, and write down what is printed.

    x = 10
    while x > 0:
        print(x)
        x -= 3
  3. A student writes this loop. What goes wrong? How do you fix it?

    lives = 3
    while lives > 0:
        print("Lives remaining:", lives)
  4. Write a while loop that asks the user to enter a password, and keeps asking until they enter "open sesame".
  5. How many times does this loop run? Trace it to find out.

    n = 1
    while n < 100:
        n *= 2
    print(n)

3   The for Loop

A for loop steps through a sequence — a list, a range of numbers, or a string — one item at a time. For each item, it runs the loop body once. When there are no more items, the loop ends automatically.

Unlike a while loop, a for loop has a built-in stopping point: the end of the sequence. You do not need to worry about updating a counter or creating an infinite loop.

🔍 Analogy: Marking a Register

A teacher calls the class register: they go through the list of names one by one, calling each name in turn. They do not need to track what number they are on — they just move to the next name until the list is finished. A for loop works exactly this way: it moves through a sequence, handling each item, and stops naturally when the list runs out.

3.1   The Structure

for variable in sequence:
    # body: runs once for each item in the sequence

The variable is a new name that holds the current item in each iteration. You choose the name — pick something descriptive. The sequence is whatever you are stepping through.

3.2   Looping Over a List

fruits = ["apple", "banana", "cherry"]

for fruit in fruits:
    print(fruit)

Output:

apple
banana
cherry

On the first iteration, fruit is "apple". On the second, it is "banana". On the third, "cherry". After that, the list is exhausted and the loop ends.

3.3   Looping Over a String

A string is also a sequence — a sequence of characters. A for loop will step through each character one at a time:

word = "Python"

for letter in word:
    print(letter)

Output:

P
y
t
h
o
n

3.4   Combining Loops and Conditionals

Loops and conditionals work naturally together. Here a loop steps through a list and a conditional picks out only certain items:

scores = [85, 42, 91, 67, 55, 78, 39, 95]

print("Students who need extra support:")
for score in scores:
    if score < 60:
        print(" -", score)

The loop visits all eight scores; the if inside it only prints the ones below 60. This pattern — loop through everything, act on some — is one of the most useful in programming.

✅ Check Your Understanding
  1. How does a for loop know when to stop? Compare this to how a while loop stops.
  2. Predict the output of this program:

    animals = ["cat", "dog", "fish", "bird"]
    for animal in animals:
        print("I have a", animal)
  3. Write a for loop that prints every letter in the string "hello" on its own line.
  4. What is printed by this program? Trace it carefully:

    numbers = [3, 7, 2, 9, 4, 6]
    total = 0
    for n in numbers:
        total += n
    print("Total:", total)
  5. Write a loop that goes through a list of names and prints only those that start with the letter "A". (Hint: use name[0] to get the first character, or name.startswith("A").)

4   Counting with range()

Very often you want to loop a specific number of times, or step through a range of numbers, without having to create a list yourself. Python's built-in range() function generates a sequence of numbers for you — and works perfectly with a for loop.

4.1   Three Forms of range()

FormWhat it generatesExampleNumbers produced
range(stop)Numbers from 0 up to (but not including) stop.range(5)0, 1, 2, 3, 4
range(start, stop)Numbers from start up to (but not including) stop.range(1, 6)1, 2, 3, 4, 5
range(start, stop, step)Numbers from start to stop, jumping by step each time.range(0, 10, 2)0, 2, 4, 6, 8
⚠️ range() does not include the stop value

range(5) gives you 0, 1, 2, 3, 4 — it stops before 5. This catches almost every beginner off-guard. To loop from 1 to 5 inclusive, write range(1, 6). A helpful way to remember: the stop value is the first number not included.

4.2   range() in Action

# Print 0 to 4
for i in range(5):
    print(i)

# Print 1 to 5
for i in range(1, 6):
    print(i)

# Print even numbers from 0 to 10
for i in range(0, 11, 2):
    print(i)

# Count backwards from 5 to 1
for i in range(5, 0, -1):
    print(i)
print("Liftoff!")
🔍 What is i?

By convention, programmers often use i as the loop variable when they only care about the count, not the value itself — it is short for "index". You will see i, j, and k used this way everywhere. If you are looping over something meaningful (a list of names, a list of scores), use a descriptive name instead. If you are just counting repetitions, i is fine.

4.3   Using range() to Repeat an Action

Sometimes you want to run a block of code a fixed number of times and you do not need the loop variable at all. This is completely valid:

# Ask for 3 quiz answers
for i in range(3):
    answer = input("Enter your answer: ")
    print("Recorded:", answer)

Here i is never used inside the loop body — the loop just ensures the block runs exactly 3 times. Some programmers write _ as the variable name in this case (for _ in range(3):) to signal that the variable is intentionally unused. Both styles are fine.

✅ Check Your Understanding
  1. What numbers does each of these produce? Write them out.

    range(4)
    range(2, 7)
    range(0, 20, 5)
    range(10, 0, -2)
  2. A student wants to print the numbers 1 through 10. They write for i in range(10):. What goes wrong? How do you fix it?
  3. Write a for loop using range() that prints the 5 times table (5, 10, 15, … up to 50).
  4. Write a loop that prints a countdown from 10 to 1, then prints "Go!".
  5. Predict the output:

    total = 0
    for i in range(1, 6):
        total += i
    print(total)

5   Choosing Between while and for

Knowing which loop to use is an important design skill. Here is the core rule:

Use for when…Use while when…
You know exactly how many times to loop, or you are stepping through a sequence.You do not know how many times you will loop — it depends on something that happens at runtime.
You have a list, string, or range() to iterate over.You are waiting for a condition to change — user input, a game state, a sensor reading.
"Do this for each item in the collection.""Keep doing this until something changes."
Examples: process every score in a list; print a times table; step through each character in a string.Examples: keep asking until valid input; run a game until the player loses; retry until a connection succeeds.
💜 A quick mental test

Ask yourself: "Do I know the number of repetitions before the loop starts?" If yes — for. If no — while. For example: "Print 10 lines" → you know the count → for. "Keep asking until the user types 'quit'" → you do not know how many tries they will need → while.

6   Controlling a Loop: break and continue

Python gives you two keywords that let you take control of a loop from inside its body. Both work in for and while loops.

6.1   break — Exit the Loop Early

break immediately stops the loop and jumps to the first line after it — no matter what the condition says or how many items are left in the sequence.

🔍 Analogy: An Emergency Exit

Imagine searching a building for someone. You check each room in turn. The moment you find them, you stop searching and leave — you do not finish checking every remaining room just because the building has more floors. break is that "found it — stop now" instruction.

names = ["Alice", "Ben", "Carol", "Dan", "Eve"]
target = "Carol"

for name in names:
    if name == target:
        print("Found:", name)
        break
    print("Checking:", name)

print("Search complete.")

Output:

Checking: Alice
Checking: Ben
Found: Carol
Search complete.

Once "Carol" is found, break exits the loop immediately. "Dan" and "Eve" are never checked.

6.2   continue — Skip to the Next Iteration

continue skips the rest of the current iteration and jumps straight back to the top of the loop to start the next one. It does not exit the loop — it just skips one pass.

🔍 Analogy: Skipping a Track

Imagine a playlist shuffling through songs. When a song you dislike comes on, you hit skip — the song ends early and the next one starts immediately. You have not stopped the playlist; you have just skipped one item. continue does the same thing: skip this item, carry on with the rest.

scores = [85, -1, 42, -1, 91, 67]

print("Valid scores:")
for score in scores:
    if score < 0:
        continue    # skip invalid entries
    print(score)

Output:

Valid scores:
85
42
91
67

The -1 entries are skipped; the loop continues normally for all other values.

6.3   break and continue in while Loops

Both keywords work in while loops too. A common pattern is a while True: loop — one that would run forever on its own — controlled entirely by a break:

# A menu that keeps running until the user chooses to quit
while True:
    choice = input("Enter command (help / quit): ").lower()

    if choice == "quit":
        print("Goodbye!")
        break
    elif choice == "help":
        print("Available commands: help, quit")
    else:
        print("Unknown command. Try 'help'.")

while True: creates an intentional infinite loop. The only way out is the break when the user types "quit". This is a widely used and perfectly acceptable pattern — as long as there is a clear, reachable break inside.

⚠️ Don't overuse break and continue

Used well, break and continue make code clearer. Used carelessly, they make loops hard to trace and debug because execution jumps around unexpectedly. Before reaching for break, ask: could I restructure the condition to stop the loop naturally instead? Before reaching for continue, ask: could I just wrap the body in an <i>if</i> statement instead? Often the answer is yes — and the result is simpler code.

✅ Check Your Understanding
  1. What is the difference between break and continue? Use a one-sentence analogy for each.
  2. Predict the output of this program:

    for i in range(1, 8):
        if i == 4:
            continue
        if i == 6:
            break
        print(i)
  3. Why is while True: not automatically a mistake? What makes it safe to use?
  4. Rewrite this code to use continue instead of nesting:

    for word in ["cat", "", "dog", "", "fish"]:
        if len(word) > 0:
            print(word.upper())
  5. Write a loop using while True and break that keeps asking the user to guess a number between 1 and 10, and stops when they guess correctly (the answer is 7).

7   Common Loop Patterns

Certain loop structures appear so frequently in real programs that they are worth learning by name. Once you recognise these patterns, you will be able to write them from memory and spot them instantly in other people's code.

7.1   The Accumulator Pattern

Create a variable before the loop. Update it inside the loop. Read the result after the loop.

# Sum all numbers in a list
scores = [78, 92, 55, 84, 67]
total = 0                    # accumulator starts at 0

for score in scores:
    total += score           # add each score to the running total

print("Total:", total)
print("Average:", total / len(scores))

7.2   The Counter Pattern

Count how many items in a sequence meet a condition.

scores = [78, 92, 55, 84, 40, 67, 38]
passing = 0                  # counter starts at 0

for score in scores:
    if score >= 60:
        passing += 1         # increment when condition is met

print(passing, "students passed out of", len(scores))

7.3   The Search Pattern

Loop through a sequence and stop as soon as you find what you are looking for.

usernames = ["alice", "bob", "carol", "dan"]
search = "carol"
found = False

for name in usernames:
    if name == search:
        found = True
        break

if found:
    print(search, "exists in the system.")
else:
    print(search, "was not found.")

7.4   The Collector Pattern

Build a new list by collecting only the items that meet a condition.

scores = [78, 92, 55, 84, 40, 67, 38]
high_scores = []             # start with an empty list

for score in scores:
    if score >= 80:
        high_scores.append(score)   # add qualifying scores

print("High scores:", high_scores)

7.5   The Input-Until-Valid Pattern

Keep asking the user for input until they provide something acceptable.

while True:
    response = input("Type yes or no: ").lower()
    if response == "yes" or response == "no":
        break
    print("Please type exactly 'yes' or 'no'.")

print("You chose:", response)
💜 Patterns are tools, not rules

You will mix and combine these patterns constantly. A single loop might accumulate a total, count a subset, and collect results all at once. Knowing the patterns by name gives you a vocabulary to think and talk about code — and a starting point when you are not sure how to begin.

8   Putting It All Together

Here is a complete program that uses both types of loops, range(), break, and three of the patterns above. Read it carefully and trace the execution before looking at the explanation below.

PASSING_SCORE = 60
NUM_STUDENTS = 4

scores = []
total = 0
failing = []

# Input loop — collect scores from the user
print("--- Score Entry ---")
for i in range(1, NUM_STUDENTS + 1):
    while True:
        score = int(input(f"Enter score for student {i} (0–100): "))
        if 0 <= score <= 100:
            break
        print("Invalid score. Please enter a number between 0 and 100.")
    scores.append(score)

# Processing loop — analyse the collected scores
for score in scores:
    total += score                     # accumulator
    if score < PASSING_SCORE:
        failing.append(score)          # collector

average = total / len(scores)

# Results
print("\n--- Results ---")
print("Scores entered:", scores)
print(f"Average score: {average:.1f}")
print(f"Students failing ({len(failing)}):", failing)

if len(failing) == 0:
    print("All students passed!")

What this program demonstrates:

  • A <strong>for</strong> loop over range() controls how many students are entered.
  • A <strong>while True</strong> loop inside the for loop validates each entry — a loop inside a loop, called a nested loop.
  • The accumulator pattern builds the total; the collector pattern gathers failing scores.
  • break exits the inner while loop the moment a valid score is entered.
  • All processing happens in a single pass through the list — one loop, three things happening at once.

9   Final Check: The Big Picture

💡 Big Idea

A <strong>while</strong> loop repeats as long as a condition is true — use it when you do not know how many iterations you will need. A <strong>for</strong> loop steps through a sequence — use it when you are iterating over a collection or a known range. <strong>range()</strong> generates number sequences for counting. <strong>break</strong> exits a loop early; <strong>continue</strong> skips the rest of the current iteration. The accumulator, counter, search, and collector patterns appear in almost every real program you will ever write.

✅ Final Check Your Understanding
  1. Explain in plain English when you would choose a for loop over a while loop, and vice versa. Give a real-world example of each.
  2. Trace this program completely. Write the value of every variable at the end of each iteration.

    result = 1
    for i in range(1, 5):
        result *= i
    print(result)
  3. This program has a bug that will cause it to crash on some inputs. Find it and fix it.

    numbers = [10, 0, 5, 0, 2]
    for n in numbers:
        print(100 / n)
  4. Write a program that asks the user to enter 5 numbers one at a time, then prints the largest number entered. Do not use Python's built-in max() function — track the largest value yourself inside the loop.
  5. What is the output of this program? Trace it step by step.

    words = ["apple", "ant", "banana", "avocado", "cherry"]
    count = 0
    for word in words:
        if word.startswith("a"):
            count += 1
        if count == 2:
            break
    print("Found", count, "words starting with 'a' before stopping.")
  6. A student wants to print every odd number from 1 to 19. They write:

    for i in range(1, 20):
        if i % 2 == 0:
            continue
        print(i)

    This works — but write a version using range() with a step argument that does not need continue at all. Which version do you think is clearer?

10   Quick-Reference Summary

ConceptSyntaxKey rule / use case
while loopwhile condition:Runs as long as condition is True. Must change state to avoid infinite loop.
for loopfor item in sequence:Steps through a sequence one item at a time. Stops automatically.
range(stop)range(5) → 0,1,2,3,4Generates numbers from 0 up to (not including) stop.
range(start, stop)range(1, 6) → 1,2,3,4,5Generates numbers from start up to (not including) stop.
range(start, stop, step)range(0, 10, 2) → 0,2,4,6,8Jumps by step each time. Use negative step to count down.
breakbreakExits the loop immediately. Works in both for and while.
continuecontinueSkips the rest of the current iteration and starts the next one.
Accumulatortotal = 0 … total += xBuild a running total or combined result across all iterations.
Countercount = 0 … count += 1Count how many items meet a condition.
SearchLoop + if … breakFind the first item that matches; stop as soon as it is found.
Collectorresult = [] … result.append(x)Build a new list of items that meet a condition.