Programming in Python · Lesson 7

Repetition Control Structures

For-loops with range(), user-controlled loops, counters, accumulators, nested loops, while-loops, infinite loops, and break.

  • loops
  • for-loops
  • range
  • while-loops
  • accumulators
  • nested-loops

Lesson purpose

Lesson 6 let programs choose between paths. This lesson lets programs repeat a block of code. Students learn count-controlled loops (Python’s for loop with range()), user-controlled loops, counters and accumulators, nested loops, and pre-test loops (Python’s while loop), including how to avoid and escape infinite loops.

Students coming from C# and JavaScript already know loops, so focus on what is different in Python: there is no three-part for (i = 0; i < n; i++) loop. A Python for loop always walks through a sequence of values, and range() produces that sequence. Python also has no do-while loop, and there is no ++ operator; use += 1.

Learning objectives

By the end of the lesson, students should be able to:

  • Identify parts of algorithms that require repetition controls.
  • Define an iterative sequence and create one with the range() function.
  • Specify how and when to use a for-loop (count-controlled loop), and write one in pseudocode and Python.
  • Identify loop control statements, loop counters, and test conditions.
  • Write a user-controlled loop that uses input to decide how many times to repeat.
  • Use loops to count and to accumulate totals, and explain the pros and cons of outputting the loop counter.
  • Draw, code, and analyze nested loops, following naming conventions for their counters.
  • Draw, identify, and code pre-test loops with while.
  • Identify infinite loops and state how to terminate them.
  • Explain the advantages and disadvantages of using break to exit a loop.

1. Loop basics

Weight training requires repetitions, and so do programs. Repetition control structures, usually called loops, repeat a block of code. You can visualize a loop as a block with an entry point, a few statements that repeat, and an exit point; in a flowchart, an arrow returns from the last statement to the top of the block.

Loops are useful for:

  • Processing a series of records in a database or the items in a list
  • Keeping a running count
  • Accumulating totals
  • Solving recursive math problems

There are two basic types of repetition control structures:

  • Count-controlled loops, which repeat a specified number of times (Python’s for loop)
  • Pre-test loops, which repeat while a condition is true (Python’s while loop)

2. Control statements and range()

The simplest repetition control structure is the count-controlled loop, which repeats a specified number of times. It begins with a control statement that sets up two things:

  • A variable for the loop counter, which tracks the number of times the loop has repeated
  • An iterative sequence for the loop counter to walk through

An iterative sequence is data in Python that can be traced linearly, one item at a time. The numbers 1, 2, 3, 4 form an iterative sequence, and so does the string "abc" (one character at a time).

The most common iterative sequence comes from the range function. range() creates a numeric sequence from up to three parameters:

  • A starting number (optional; defaults to 0)
  • An ending number (required; never included in the sequence)
  • An increment (optional; defaults to 1), used to skip numbers
Range call Iterative sequence
range(10) 0 1 2 3 4 5 6 7 8 9
range(1, 10) 1 2 3 4 5 6 7 8 9
range(1, 10, 2) 1 3 5 7 9
range(0, 10, 2) 0 2 4 6 8

Key rule: range() goes up to but not including the ending number. This is the same “stop before the end” rule students saw with string slices in Lesson 5.

Check for understanding: How many numbers are in range(5)? Five: 0, 1, 2, 3, 4.

Extension: a negative increment counts down. range(10, 0, -1) produces 10 down to 1.

3. For-loops

The for-loop is a count-controlled loop that is appropriate when you know how many times the loop should repeat.

Flowchart logic:

  1. Set up the iterative sequence with range() and a counter variable.
  2. Is the counter still in the sequence? If True, run the loop’s statements.
  3. Advance the counter to the next value and check again.
  4. When the sequence is used up (False), exit the loop.

In pseudocode, use wording such as “repeat four times:” and indent the repeated statements:

repeat twice:
    Display "Lift", "Pause", and "Lower"

Expected output:

Lift
Pause
Lower

Lift
Pause
Lower

Check for understanding: What range() call matches “repeat twice”? range(2) (or any range with two values, such as range(1, 3)).

Python syntax

for i in range(iteration):
    statement1
    statement2

Rules and best practices from the book:

  • The loop variable should be a simple identifier, usually i (short for iteration, a synonym for repetition).
  • The range() function provides the sequence for i to iterate over.
  • The loop variable will visit each value in the sequence provided by range(), even if you change the loop variable inside the loop.
  • Avoid modifying the loop counter variable inside the loop. For example, do not assign to i inside the loop.

Example: three repetitions of the bench press

for i in range(1, 4):
    print("Lift")
    print("Pause")
    print("Lower")
    print()

Output:

Lift
Pause
Lower

Lift
Pause
Lower

Lift
Pause
Lower
  • range(1, 4) produces 1, 2, 3, so the body runs three times.
  • The empty print() outputs a blank line between repetitions.
  • Every indented line is part of the loop body; the colon and indentation work exactly like the if blocks in Lesson 6.

C#/JavaScript connection: for i in range(1, 4): is the equivalent of for (int i = 1; i < 4; i++). Python’s for is really a “for each” loop, like foreach in C# or for...of in JavaScript.

4. User-controlled loops

A user-controlled loop gets the value for range() from user input at runtime, so the user decides how many times the loop repeats. Users can control both for-loops and pre-test loops.

Pseudocode:

Ask weightlifter "How many reps? " and store in a variable
repeat based on input:
    Display "Lift, pause, lower"
reps = int(input("How many reps? "))
for i in range(reps):
    print("Lift, pause, lower")

Sample run:

How many reps? 5
Lift, pause, lower
Lift, pause, lower
Lift, pause, lower
Lift, pause, lower
Lift, pause, lower
  • int() is required because range() needs an integer and input() returns a string.
  • The variable reps appears in both the input statement and the range() call; that connection is what makes the loop user-controlled.

5. Counters

Count-controlled loops have a built-in counter that can be used for algorithms that count, such as counting by twos or printing multiplication tables. Set the counting pattern with all three range() parameters:

for i in range(2, 11, 2):
    print(i)

Output:

2
4
6
8
10
  • Start at 2, stop before 11, and increase by 2 each time.
  • The ending value is 11 (not 10) so that 10 is included.

Using a separate counter variable

Outputting the loop counter works, but the book recommends avoiding the loop counter in other statements within the loop, because it could be inadvertently changed. Instead, set up a separate variable for output and increment it inside the loop:

count_out = 0
for i in range(2, 11, 2):
    count_out += 2
    print(count_out)

The output is the same: 2, 4, 6, 8, 10.

  • count_out starts at 0 before the loop.
  • count_out += 2 is shorthand for count_out = count_out + 2. (Python has no ++ operator.)

Check for understanding: Which variable is used as the counter for output? count_out.

Teaching note: weigh the trade-off with students. Printing i directly is shorter and very common in real Python code; a separate counter is safer when the loop body grows or when the counter must continue after the loop ends.

6. Accumulators

Loops can also accumulate a total by repeatedly adding values. Example: a lifter bench-presses 15-pound weights in each hand and wants to know the total weight lifted.

Ask how many reps and store response in a variable
Ask how much the weights weigh and store response in a variable
Initialize a total weight variable at 0
Repeat based on input:
    Increase the total weight by twice the weight
    Display the rep number and total weight so far

An accumulator always involves two steps:

  1. Initialize the accumulator to a starting value (0 for addition) before the loop.
  2. Increase the accumulator by some amount inside the loop.
total_weight = 0
reps = int(input("How many reps? "))
weight = int(input("What size weights are you using? "))
for i in range(1, reps + 1):
    total_weight = total_weight + (weight * 2)
    print("Rep", i, total_weight, "lbs so far.")
print("Your total lift is:", total_weight, "lbs.")

Sample run:

How many reps? 3
What size weights are you using? 15
Rep 1 30 lbs so far.
Rep 2 60 lbs so far.
Rep 3 90 lbs so far.
Your total lift is: 90 lbs.
  • range(1, reps + 1) numbers the reps 1 through 3 instead of 0 through 2.
  • The final print() is not indented, so it runs once, after the loop finishes.

Check for understanding: Why is the weight multiplied by 2? There is a weight in each hand, so each rep lifts two weights.

Common bug to demonstrate: move total_weight = 0 inside the loop, and the total resets every rep.

7. Nested loops

A nested loop is a loop within a loop. Each loop has its own control statement and loop counter. Weight training is again a helpful model: a workout has sets (outer loop), and each set has reps (inner loop). For three sets of four reps, the outer loop runs 3 times and the inner loop runs 4 times for each outer iteration, 12 reps in all.

Flowchart logic: the computer enters the outer loop, then runs the entire inner loop, then returns to the outer loop for its next iteration, which runs the entire inner loop again.

In pseudocode, the inner loop is indented under the outer loop:

Ask for the weight size and store response in a variable
Ask for how many sets and store response in a variable
Ask for how many reps per set and store response in a variable
Repeat based on the number of sets:
    Display the set number
    Repeat based on the number of reps:
        Increase the total weight by twice the weight size
        Display the rep number and total weight lifted so far

Check for understanding: When the user enters 3 for the number of sets, how many times does the outer loop iterate? Three.

Naming the counters

Each loop control variable must be unique. Programmers typically use i for the outer loop and j for the inner loop. The book’s example uses more descriptive names, s for sets and r for reps.

total_weight = 0
weight = int(input("What size weights are you using? "))
sets = int(input("How many sets? "))
reps = int(input("How many reps per set? "))
for s in range(1, sets + 1):
    print("Set:", s)
    for r in range(1, reps + 1):
        total_weight = total_weight + (weight * 2)
        print("   Rep:", r, "Progress:", total_weight, "lbs.")
print("Your total lift is:", total_weight, "lbs.")

Sample run:

What size weights are you using? 15
How many sets? 3
How many reps per set? 2
Set: 1
   Rep: 1 Progress: 30 lbs.
   Rep: 2 Progress: 60 lbs.
Set: 2
   Rep: 1 Progress: 90 lbs.
   Rep: 2 Progress: 120 lbs.
Set: 3
   Rep: 1 Progress: 150 lbs.
   Rep: 2 Progress: 180 lbs.
Your total lift is: 180 lbs.

Check for understanding: Why isn’t “Set: 1” printed on every rep line? The print("Set:", s) statement is in the outer loop body, before the inner loop starts, so it runs once per set. Only statements indented inside the inner loop run once per rep.

Warning from the book’s infinite-loop list: using the same counter variable for the inner and outer loops causes bugs. Always give each loop its own counter.

8. Pre-test loops (while-loops)

Not every loop is controlled by a counter. A condition-controlled loop is regulated by a Boolean expression, like the conditions in Lesson 6’s if statements.

A pre-test loop begins with a condition. It executes only if the condition is true, and it keeps executing until the condition is no longer True or until the loop encounters a break statement. Because the test comes first, the body may run zero times.

Pre-test loops are ideal for validating input:

Ask user for input.
If the input is not valid, output a message that asks for a valid entry.
Check the entry again and repeat until the entry is valid.

Pseudocode for pre-test loops typically uses the words while or until:

Request the number of reps and store in a variable.
While the number of reps is less than 1 or greater than 25:
    Display an error message and request the number of reps again
Display a message which shows the number of valid reps

A while-loop is Python’s pre-test loop.

while condition:
    statement1
    statement2
reps = int(input("Enter the number of reps for this lifting exercise: "))
while reps < 1 or reps > 25:
    reps = int(input("Try again. Reps have to be in the range 1 to 25: "))
print("Okay, you want to do", reps, "reps.")

Sample run:

Enter the number of reps for this lifting exercise: 38
Try again. Reps have to be in the range 1 to 25: 20
Okay, you want to do 20 reps.
  • Line 1 gets the first value before the loop (sometimes called a priming read).
  • Line 2 tests the value. If it is out of range, the body runs.
  • Line 3 gets a new value and stores it back in reps, so the condition can eventually become False.
  • If the first value is already valid, the loop body never runs.

For vs. while: use for when you know (or the user tells you) how many times to repeat; use while when repetition depends on a condition, such as “until the input is valid.”

C#/JavaScript connection: Python has no do-while (post-test) loop. The priming-read pattern above, or a while True: loop with break, fills that role.

9. Infinite loops

An infinite loop never ends on its own. Causes include:

  • Invalid input that does not end an input loop
  • Input that changes the value of the loop counter
  • A programmer error in the loop’s conditional statement
  • Using the loop counter variable in a mathematical operation inside the loop
  • Using the same loop counter variable for the inner and outer loops of a nested loop

Trace this code to find the error:

reps = int(input("Enter the number of reps: "))
while reps < 1 or reps > 25:
    int(input("Try again. Enter a number in the range 1 to 25: "))
print("Okay, you want to do", reps, "reps.")

If the user enters 0, the prompt repeats forever:

Enter the number of reps: 0
Try again. Enter a number in the range 1 to 25:
Try again. Enter a number in the range 1 to 25:
Try again. Enter a number in the range 1 to 25:
...

The error: line 3 reads and converts the new input but never assigns it to reps. The loop condition checks reps, which stays 0, so the condition is always True. The fix is reps = int(input(...)).

Note on the book’s version: its last line is print("Okay, you want to do " + reps + " reps."). Because reps is an integer, that line would raise a TypeError even if the loop ended (Lesson 5: you cannot concatenate str and int). The version above uses commas instead.

To manually stop a program stuck in an infinite loop, press Ctrl+C in the terminal, or use the Stop button in the IDE or online compiler.

10. Breaking out of loops

Users should never have to press Ctrl+C. A program should always provide a clean exit path, preferably within the logic of the loop’s control statement.

Preferred: build the exit into the condition

reps = int(input("Enter the number of reps: "))
while (reps < 1 or reps > 25) and (reps != 999):
    reps = int(input("Try again. Enter a number in the range 1 to 25, or enter 999 to exit: "))
if reps == 999:
    print("Bye.")
else:
    print("Okay, you want to do", reps, "reps.")

Sample run:

Enter the number of reps: 0
Try again. Enter a number in the range 1 to 25, or enter 999 to exit: 999
Bye.
  • The loop continues only while the value is out of range and is not the exit value 999.
  • The if/else after the loop handles the two ways the loop can end: quitting or a valid entry.
  • 999 is a sentinel value, a special value that signals “stop.”

Using break

A break statement exits the loop immediately, but it can have unintended consequences:

reps = int(input("Enter the number of reps: "))
while (reps < 1 or reps > 25):
    reps = int(input("Try again. Enter a number in the range 1 to 25, or enter 999 to exit: "))
    if reps == 999:
        print("Bye.")
        break
print("Okay, you want to do", reps, "reps.")

Sample run:

Enter the number of reps: 0
Try again. Enter a number in the range 1 to 25, or enter 999 to exit: 999
Bye.
Okay, you want to do 999 reps.

Check for understanding: What is wrong with this logic? break exits the loop, but execution continues with the statement after the loop, so the program says “Bye.” and then announces 999 reps.

The book’s guidance: because break can have unexpected effects, it is best practice to design the loop’s control condition to provide a graceful exit. Professional developers use break widely, though, so be flexible and follow each project’s specifications. (A common, clean professional pattern is while True: with a single, clearly placed break.)

Classroom application

  1. Range prediction. Show range(3), range(2, 8), range(5, 50, 5), and range(10, 0, -2). Students write the sequences, then check with print(list(range(...))).
  2. Multiplication table. Ask the user for a number and print its table from 1 to 12 with a for-loop.
  3. Grade average. Ask how many scores to enter, use a for-loop to read each one, accumulate the total, and print the average. Discuss where the accumulator must be initialized.
  4. Rectangle of stars. Use nested loops to print a rectangle of * characters with user-chosen rows and columns (print("*", end="") inside, print() after the inner loop).
  5. Validated menu. Wrap the Lesson 6 phone-menu if/elif in a while-loop that repeats until the user enters 0.
  6. Bug hunt. Give students the infinite-loop example and the break example; have them explain each bug and fix it.

Common misconceptions

  • “range(1, 10) includes 10.” The ending number is never included.
  • “range(5) starts at 1.” It starts at 0 unless a starting number is given.
  • “Changing i inside a for-loop changes the next iteration.” The next value always comes from the sequence; reassigning i only affects the rest of the current pass. Avoid it.
  • “i++ works in Python.” Use i += 1.
  • “A while-loop always runs at least once.” It is a pre-test loop; if the condition starts False, the body never runs.
  • “Reading input in the loop is enough.” The new value must be assigned to the variable the condition checks, or the loop never ends.
  • “Initialize the accumulator inside the loop.” That resets the total every iteration; initialize it before the loop.
  • “Nested loops can share a counter.” Each loop needs its own counter variable.
  • “break ends the program.” break exits only the innermost loop; execution continues after that loop.

Lesson summary

  • A repetition control structure (loop) has an entry point, statements that repeat, and an exit point.
  • A count-controlled loop repeats a specified number of times and begins with a control statement that sets up a loop counter.
  • The for-loop is the count-controlled loop to use when you know how many times to repeat.
  • range(start, end, increment) creates the iterative sequence; start defaults to 0, increment to 1, and the end is never included.
  • Users can control how many times a loop repeats by providing input for the loop’s range or condition.
  • Loops can output counting sequences, and accumulators sum values: initialize before the loop, update inside it.
  • Nested loops are loops within loops; the inner loop completes fully for each iteration of the outer loop, and each uses its own counter.
  • A pre-test loop (while-loop) runs only while its condition is true and is ideal for input validation.
  • An infinite loop never ends on its own; stop it with Ctrl+C or the IDE’s Stop button, and prevent it by making sure the loop condition can become false.
  • break exits a loop, but a clean exit built into the loop’s control condition is usually the better design.