DEV Community

Navas Herbert
Navas Herbert

Posted on

Python Week 3: We Stopped Repeating Ourselves (Loops!)

I started this session with a challenge.

"Jose," I said, "print the names of all 40 students in this dataset - one per line."

He looked at me. Then at his keyboard. Then started typing print("Amina").

I let him get to the third name before I stopped him.

"What if there were 10,000 students?"

Silence.

"What if the list changed every week?"

More silence.

That's the setup for loops. You don't teach loops by explaining them - you first make people feel the pain of not having them. Then the solution lands differently.


The for Loop: Working Through a List

The for loop is Python's way of saying: go through every item in this collection and do something with each one.

My analogy: a class register. The teacher calls each name in order, marks attendance, moves to the next. They don't skip anyone. They don't stop early. They go through the whole list.

students = ["Amina", "Brian", "Njeri", "Kamau", "Wanjiku"]

for student in students:
    print(f"Good morning, {student}! 👋")
Enter fullscreen mode Exit fullscreen mode
Good morning, Amina! 👋
Good morning, Brian! 👋
Good morning, Njeri! 👋
Good morning, Kamau! 👋
Good morning, Wanjiku! 👋
Enter fullscreen mode Exit fullscreen mode

Five names. One loop. If the list had 10,000 names, same code - still works.

Jose closed his half-written print() statements and deleted them. That reaction is why I love teaching this session.


range(): Counting Without a List

Sometimes you don't have a list of items - you just want to repeat something a specific number of times. That's what range() is for.

for i in range(5):
    print(f"Attempt {i + 1}")
Enter fullscreen mode Exit fullscreen mode
Attempt 1
Attempt 2
Attempt 3
Attempt 4
Attempt 5
Enter fullscreen mode Exit fullscreen mode

Then came the question I wait for every cohort.

"Why does range(5) go from 0 to 4? Why not 1 to 5?"

Because Python counts like a programmer - starting from zero. range(5) means "give me 5 numbers starting at 0" - so 0, 1, 2, 3, 4.

If you want 1 to 5, you tell it explicitly:

for i in range(1, 6):
    print(i)
Enter fullscreen mode Exit fullscreen mode
1
2
3
4
5
Enter fullscreen mode Exit fullscreen mode

You can even count in steps:

# Count in 10s - like a matatu filling up every 10km
for km in range(0, 51, 10):
    print(f"Distance covered: {km} km")
Enter fullscreen mode Exit fullscreen mode
Distance covered: 0 km
Distance covered: 10 km
Distance covered: 20 km
Distance covered: 30 km
Distance covered: 40 km
Distance covered: 50 km
Enter fullscreen mode Exit fullscreen mode

Doing Real Work Inside a Loop

A loop is only useful if you do something meaningful inside it. We levelled up from printing names to processing data:

scores = [78, 45, 92, 61, 55, 88, 34, 73]
total = 0

for score in scores:
    total = total + score

average = total / len(scores)
print(f"Class average: {average:.1f}")
Enter fullscreen mode Exit fullscreen mode
Class average: 65.8
Enter fullscreen mode Exit fullscreen mode

Then we added a conditional inside the loop - finding students who failed:

scores = [78, 45, 92, 61, 55, 88, 34, 73]

print("Students who need support:")
for i in range(len(scores)):
    if scores[i] < 50:
        print(f"  Student {i + 1}: scored {scores[i]} - below pass mark")
Enter fullscreen mode Exit fullscreen mode
Students who need support:
  Student 2: scored 45 - below pass mark
  Student 7: scored 34 - below pass mark
Enter fullscreen mode Exit fullscreen mode

This is where students started to see it. A loop plus a conditional is already a mini data pipeline. You're iterating through records, applying a rule, flagging what matters.


The while Loop: Keep Going Until Something Changes

The for loop goes through a fixed collection. The while loop is different - it keeps running as long as a condition is true, and you don't always know in advance how many times that will be.

My analogy: a matatu waiting at the stage. It doesn't leave after a fixed number of passengers - it waits until it's full. While there's space, keep accepting passengers.

passengers = 0
capacity = 14

while passengers < capacity:
    passengers += 1
    print(f"Passenger {passengers} boards. Seats remaining: {capacity - passengers}")

print("Matatu is full. Twende!")
Enter fullscreen mode Exit fullscreen mode
Passenger 1 boards. Seats remaining: 13
Passenger 2 boards. Seats remaining: 12
...
Passenger 14 boards. Seats remaining: 0
Matatu is full. Twende! 
Enter fullscreen mode Exit fullscreen mode

A more practical use - a simple login system that keeps asking until you get it right:

password = "lux2024"
attempts = 0

while True:
    entry = input("Enter password: ")
    attempts += 1

    if entry == password:
        print(f"✅ Access granted after {attempts} attempt(s).")
        break
    else:
        print("❌ Wrong password. Try again.")
Enter fullscreen mode Exit fullscreen mode
Enter password: wrongpass
❌ Wrong password. Try again.
Enter password: lux2024
✅ Access granted after 2 attempt(s).
Enter fullscreen mode Exit fullscreen mode

The Infinite Loop Nobody Saw Coming

This was the moment of the session.

One student - Aisha - was building the login checker and forgot the break. Her loop just kept asking for the password. Forever. Her laptop stopped responding to anything else.

"How do I stop it?!"

Ctrl + C. Always Ctrl + C.

She pressed it. The program stopped. The room exhaled.

I told everyone to write Ctrl + C at the top of their notes and circle it. It's the emergency exit for every infinite loop - and you will need it at some point. Better to learn it when Aisha accidentally teaches you than when you're alone at midnight wondering why your computer is hot.

The lesson from Aisha's loop: every while True must have a break inside it. Without a way out, the loop runs until you force-quit the program or your laptop gives up.


break and continue: Taking Control of the Loop

Once students understood that loops run to completion, I showed them two ways to interrupt that:

break - stop the loop entirely and exit:

# Search for a student in the register
register = ["Amina", "Brian", "Njeri", "Kamau", "Wanjiku"]
target = "Njeri"

for student in register:
    if student == target:
        print(f"Found {target}! ✅")
        break   # No need to keep searching
    print(f"Checking {student}...")
Enter fullscreen mode Exit fullscreen mode
Checking Amina...
Checking Brian...
Found Njeri! ✅
Enter fullscreen mode Exit fullscreen mode

continue - skip this item and move to the next one:

# Print all scores, but skip anyone who was absent (score = 0)
scores = [78, 0, 92, 0, 55, 88]

for score in scores:
    if score == 0:
        continue   # Skip absent students
    print(f"Score: {score}")
Enter fullscreen mode Exit fullscreen mode
Score: 78
Score: 92
Score: 55
Score: 88
Enter fullscreen mode Exit fullscreen mode

The analogy that landed for continue: a teacher calling the register and the student is absent. You don't stop the whole class - you just say "absent" and move to the next name.


Nested Loops: A Loop Inside a Loop

I saved this for the end - the concept that always gets a dramatic reaction.

# Multiplication table (3x3 preview)
for i in range(1, 4):
    for j in range(1, 4):
        print(f"{i} x {j} = {i * j}")
    print("---")
Enter fullscreen mode Exit fullscreen mode
1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
---
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
---
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
---
Enter fullscreen mode Exit fullscreen mode

"The outer loop runs - and every time it does, the inner loop runs all the way through."

You could see people mentally tracing the logic. I gave them a minute to sit with it before moving on. Some concepts need a moment, not a faster explanation.

A practical example - checking every student against every subject:

students = ["Amina", "Brian", "Njeri"]
subjects = ["Maths", "English", "Science"]

for student in students:
    for subject in subjects:
        print(f"{student}{subject}")
    print()
Enter fullscreen mode Exit fullscreen mode
Amina → Maths
Amina → English
Amina → Science

Brian → Maths
Brian → English
Brian → Science

Njeri → Maths
Njeri → English
Njeri → Science
Enter fullscreen mode Exit fullscreen mode

Practice Problems

Easy:

# 1. Print numbers 1 to 20 using a for loop and range()
# 2. Print only even numbers between 1 and 30
# 3. Loop through this list and print each item in uppercase:
#    groceries = ["unga", "sukari", "mafuta", "chumvi"]
Enter fullscreen mode Exit fullscreen mode

Medium:

# A simple ATM PIN checker - give the user 3 attempts
correct_pin = "4821"
attempts = 0
max_attempts = 3

while attempts < max_attempts:
    pin = input("Enter your PIN: ")
    attempts += 1

    if pin == correct_pin:
        print("PIN accepted. Welcome.")
        break
    else:
        remaining = max_attempts - attempts
        if remaining > 0:
            print(f"Wrong PIN. {remaining} attempt(s) left.")
        else:
            print("Account locked. Please visit your branch.")
Enter fullscreen mode Exit fullscreen mode

Challenge:

# Sales summary - loop through a list of daily sales,
# calculate total, find the highest day, count days below target

daily_sales = [12400, 8750, 15200, 6300, 19800, 11050, 9400]
target = 10000

# Your code here:
# 1. Total sales for the week
# 2. Best day (highest sales)
# 3. How many days missed the target
Enter fullscreen mode Exit fullscreen mode

What I Noticed Teaching This Session

1. The pain-first setup works every time. Making Jose start writing 40 print() statements - even for just 3 names - made the loop feel like a rescue, not a concept.

2. Aisha's infinite loop was the best teaching moment of the week. An accident in front of the class, handled calmly, teaches Ctrl + C and loop safety more effectively than any slide ever could. I didn't plan it. I didn't need to.

3. Students started thinking like data people. When we looped through scores and flagged students below 50, someone said: "This is basically filtering - like SQL WHERE." That connection was electric. That's exactly what it is.

4. break and continue need contrast to make sense. Showing them without break (loop continues past the found item) before showing with break made the difference immediately visible.


What's Coming in Week 4: Functions

Right now our programs do things — but they can't remember how to do them. If we need to calculate a grade three times in different places, we write the logic three times. That's wrong.

Functions fix this:

def calculate_grade(score):
    if score >= 80:
        return "A"
    elif score >= 70:
        return "B"
    elif score >= 60:
        return "C"
    elif score >= 50:
        return "D"
    else:
        return "F"

print(calculate_grade(85))   # A
print(calculate_grade(62))   # C
print(calculate_grade(41))   # F
Enter fullscreen mode Exit fullscreen mode

Write it once. Use it anywhere. That's next week.


Try It Yourself

Start with the ATM PIN checker - it combines everything from Week 2 (conditionals) and Week 3 (while loops). If that runs cleanly, you're ready for functions.


I'm a data trainer in Nairobi running a full data programme -
Python foundations → Data Science or Data Engineering specialisations.
I write weekly about what we covered, what worked, and what surprised me.
Follow along or drop your questions in the comments.

Top comments (0)