Chapter 5: Repeating Things — Loops
At the end of Chapter 4 you built a number guessing game. The user guesses once, gets feedback, and the program ends. But a real guessing game lets you keep trying until you get it right.
That's what loops do. A loop runs a block of code again and again — as many times as you need. Without loops, you'd have to copy and paste the same code dozens of times. With loops, you write it once and let Python repeat it.
This is one of the most important ideas in all of programming. Let's dig in.
Why Loops Exist
Imagine printing every number from 1 to 100. Without a loop:
print(1)
print(2)
print(3)
# ... 97 more lines
print(100)
That's 100 lines of nearly identical code. Now with a loop:
for i in range(1, 101):
print(i)
Two lines. Same result. That's the power of loops.
But loops aren't just for counting. They're for processing every item in a list, reading every line in a file, repeating a question until you get a valid answer, and a thousand other patterns you'll use every day.
Python has two kinds of loops: for and while. You'll use both.
for Loops — Repeating a Known Number of Times
A for loop goes through a sequence — a range of numbers, a list, a string, anything you can iterate over — and runs the indented block once for each item.
for i in [1, 2, 3, 4, 5]:
print(i)
Output:
1
2
3
4
5
The variable i takes each value from the list in turn. First it's 1, the block runs. Then it's 2, the block runs. And so on until the list is exhausted.
The variable name i is just a convention for "index" or "iteration." You can call it anything.
for number in [10, 20, 30]:
print(f"The number is {number}")
Output:
The number is 10
The number is 20
The number is 30
Your turn: Write a for loop that prints these three words, one per line: "Python", "is", "fun".
range() — Generating Sequences of Numbers
Typing out a list like [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] is tedious. range() generates a sequence of numbers on demand, without storing them all in memory.
range(stop) — Start at 0, count up to (but not including) stop
for i in range(5):
print(i)
Output:
0
1
2
3
4
range(5) gives you 0, 1, 2, 3, 4. It stops before 5. This trips up beginners constantly — remember: the stop value is excluded.
range(start, stop) — Control where you start
for i in range(1, 6):
print(i)
Output:
1
2
3
4
5
Now it starts at 1 and stops before 6. Much more natural for counting things humans care about.
range(start, stop, step) — Control the step size
for i in range(0, 11, 2):
print(i)
Output:
0
2
4
6
8
10
The step is 2, so we jump by 2 each time. You can use any step, including negative — which lets you count backwards.
for i in range(10, 0, -1):
print(i)
print("Blastoff!")
Output:
10
9
8
7
6
5
4
3
2
1
Blastoff!
Your turn: Use range() to:
- Print all odd numbers from 1 to 19.
- Print a countdown from 20 to 0, stepping by 5 (20, 15, 10, 5, 0).
Doing Real Work Inside a Loop
The real power of loops is doing something useful on each iteration — not just printing a counter.
Summing numbers
total = 0
for number in range(1, 11):
total = total + number
print(f"Sum of 1 to 10 is: {total}")
Output:
Sum of 1 to 10 is: 55
Before the loop, total is 0. On each pass, we add the current number to total. After the loop, total holds the sum of everything.
Multiplication table
n = 7
for i in range(1, 11):
print(f"{n} x {i} = {n * i}")
Output:
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70
Looping over a string
Strings are sequences too. You can loop over every character.
for letter in "Python":
print(letter)
Output:
P
y
t
h
o
n
Your turn: Write a loop that calculates and prints the factorial of a number. (Factorial of 5 = 1 x 2 x 3 x 4 x 5 = 120.) Start with result = 1 and multiply on each iteration.
while Loops — Repeating Until a Condition Changes
A while loop keeps running as long as its condition is True. You use it when you don't know in advance how many times you'll need to repeat — you just know when to stop.
count = 0
while count < 5:
print(f"count is {count}")
count += 1
Output:
count is 0
count is 1
count is 2
count is 3
count is 4
Python checks the condition before each iteration. If it's True, the block runs. If it's False, the loop ends. Here, once count reaches 5, count < 5 becomes False and we stop.
The critical rule: Something inside the loop must eventually make the condition False. Here count += 1 does that. Without it, count would never change, the condition would stay True forever, and you'd have an infinite loop.
Waiting for valid input
This is the classic use case for while — keep asking until the user gives you what you need.
age = -1
while age < 0:
age = int(input("Enter your age (must be 0 or more): "))
if age < 0:
print("That's not a valid age. Try again.")
print(f"Your age is {age}.")
Sample run:
Enter your age (must be 0 or more): -5
That's not a valid age. Try again.
Enter your age (must be 0 or more): -1
That's not a valid age. Try again.
Enter your age (must be 0 or more): 28
Your age is 28.
The program will not move on until the user gives a non-negative number. This pattern — validate input in a loop — is everywhere in real software.
Your turn: Write a while loop that keeps asking the user to enter a password until they type the correct one ("opensesame"). When they get it right, print "Access granted!"
Infinite Loops and How to Avoid Them
An infinite loop runs forever because its condition never becomes False.
# DANGER — this runs forever
while True:
print("This never stops!")
If you run this by accident, press Ctrl+C in the terminal to force-stop it.
But infinite loops aren't always a mistake. Sometimes you want to loop forever and use break to exit at the right moment (more on that below). Many real programs — servers, games, dashboards — run in a loop intentionally: "keep running until the user quits."
while True:
command = input("Enter command (or 'quit' to exit): ")
if command == "quit":
print("Goodbye!")
break
print(f"You typed: {command}")
Sample run:
Enter command (or 'quit' to exit): hello
You typed: hello
Enter command (or 'quit' to exit): test
You typed: test
Enter command (or 'quit' to exit): quit
Goodbye!
This pattern — while True with a break to exit — is one of the most useful structures in all of Python.
break — Stop the Loop Early
break exits the loop immediately, no matter where you are in the iteration.
for i in range(10):
if i == 5:
break
print(i)
print("Loop ended.")
Output:
0
1
2
3
4
Loop ended.
When i reaches 5, break fires and the loop ends. The print("Loop ended.") runs because it's outside the loop.
A real example: searching for something in a sequence.
names = ["Alice", "Bob", "Carlos", "Diana", "Eve"]
target = "Carlos"
for name in names:
print(f"Checking {name}...")
if name == target:
print(f"Found {target}!")
break
Output:
Checking Alice...
Checking Bob...
Checking Carlos...
Found Carlos!
Once we find the target, there's no reason to keep checking. break stops the loop early.
continue — Skip One Iteration
continue skips the rest of the current iteration and jumps straight to the next one. The loop doesn't stop — it just skips this pass.
for i in range(10):
if i % 2 == 0:
continue # skip even numbers
print(i)
Output:
1
3
5
7
9
When i is even, continue fires and we skip the print. When i is odd, nothing skips the print, so it runs.
Another example: printing only the positive numbers from a mixed list.
numbers = [4, -2, 7, -1, 0, 9, -5, 3]
for n in numbers:
if n <= 0:
continue
print(n)
Output:
4
7
9
3
else on a Loop — The Secret Clause
Python loops have a feature most beginners never learn: an else clause. The else block runs after the loop finishes normally — meaning it does not run if the loop was stopped by a break.
for i in range(5):
print(i)
else:
print("Loop finished normally.")
Output:
0
1
2
3
4
Loop finished normally.
Now with a break:
for i in range(5):
if i == 3:
break
print(i)
else:
print("Loop finished normally.") # this will NOT print
Output:
0
1
2
The else didn't run because break stopped the loop early.
This is incredibly useful for "search and report if not found" patterns:
names = ["Alice", "Bob", "Diana", "Eve"]
target = "Carlos"
for name in names:
if name == target:
print(f"Found {target}!")
break
else:
print(f"{target} was not found in the list.")
Output:
Carlos was not found in the list.
Without the else clause, you'd need an extra variable to track whether you found the item. With it, Python handles the logic for you.
for vs while — When to Use Each
| Situation | Use |
|---|---|
| You know exactly how many times to repeat | for |
| You're going through a sequence (list, string, range) | for |
| You're repeating until a condition changes | while |
| You're waiting for user input | while |
| You want to loop forever until a break | while True |
If you can write it cleanly as a for loop, prefer for. It's more readable and harder to accidentally infinite-loop.
Nested Loops
You can put a loop inside another loop. The inner loop runs completely for every single iteration of the outer loop.
for row in range(1, 4):
for col in range(1, 4):
print(f"({row},{col})", end=" ")
print() # new line after each row
Output:
(1,1) (1,2) (1,3)
(2,1) (2,2) (2,3)
(3,1) (3,2) (3,3)
The end=" " in print() tells Python not to add a newline — just a space — after each item. The plain print() at the end of the outer loop adds the newline to finish each row.
Nested loops are essential for working with grids, tables, and combinations. But be careful: if the outer loop runs 100 times and the inner loop runs 100 times, that's 10,000 total iterations. Nesting goes deep fast.
Your turn: Use nested loops to print a multiplication table from 1x1 to 5x5. Each row should show all five products for that multiplier.
Putting It All Together: The Guessing Game
Remember the guessing game from Chapter 4 that only let you guess once? Here it is, completed with a loop.
import random
secret = random.randint(1, 100)
attempts = 0
max_attempts = 7
print("I'm thinking of a number between 1 and 100.")
print(f"You have {max_attempts} attempts.")
while attempts < max_attempts:
guess = int(input("Your guess: "))
attempts += 1
if guess < secret:
print(f"Too low! ({max_attempts - attempts} attempts left)")
elif guess > secret:
print(f"Too high! ({max_attempts - attempts} attempts left)")
else:
print(f"You got it in {attempts} attempt(s)! The number was {secret}.")
break
else:
print(f"Out of attempts! The number was {secret}.")
Sample run:
I'm thinking of a number between 1 and 100.
You have 7 attempts.
Your guess: 50
Too high! (6 attempts left)
Your guess: 25
Too low! (5 attempts left)
Your guess: 37
Too low! (4 attempts left)
Your guess: 43
You got it in 4 attempt(s)! The number was 43.
Look at what's happening here:
while attempts < max_attemptskeeps the loop going until attempts run outbreakexits the loop when the player wins- The
elseon thewhileloop runs only if attempts ran out (i.e.,breakwas never hit) random.randint(1, 100)picks a random number — you'll learn more aboutrandomin Chapter 16
This is a complete, playable game. Built with tools you now know.
What You Learned in This Chapter
forloops iterate over a sequence — a list, arange(), or any iterable.range(stop)starts at 0.range(start, stop)gives you control.range(start, stop, step)lets you skip or count backwards.whileloops repeat as long as a condition isTrue. Use them when you don't know the count in advance.while Truewith abreakis the standard pattern for "loop until done."breakexits the loop immediately.continueskips the rest of the current iteration and moves to the next.elseon a loop runs after the loop finishes normally — it's skipped ifbreakfired.- Nested loops let you work with rows and columns, grids, and combinations.
- Always make sure a
whileloop's condition will eventually becomeFalse.
What's Next?
Your programs can now repeat. But they're still working with one value at a time — one number, one name, one score.
In Chapter 6 you'll learn about lists — a way to store many values in a single variable. You'll combine lists with loops and suddenly be able to process hundreds of items with just a few lines of code. It's where things start to feel truly powerful.
Your turn: Write a program that asks the user to enter numbers one at a time. After each number, add it to a running total and print the current total. Stop when the user types 0. At the end, print how many numbers they entered and what the total was. (Hint: use while True and break.)