For, Range, and Iteration Patterns
Key Takeaways
- A for loop assigns the next item from an iterable to the loop variable on each iteration.
- range(stop) starts at 0 and excludes stop; range(start, stop, step) also excludes stop.
- A negative range step counts downward only when the start and stop values make that direction possible.
- Loop variables keep their last assigned value after a loop that ran at least once.
- PCEP range traps usually involve excluded stop values, empty ranges, negative steps, or confusing values with indexes.
What a for loop does
A for loop takes values from an iterable one at a time. On each iteration, Python assigns the next value to the loop variable and runs the indented block.
for ch in 'PCEP':
print(ch)
The loop variable ch becomes 'P', then 'C', then 'E', then 'P'. The loop does not need a manual index unless the code actually needs positions.
The range function
range() is the most common PCEP loop source. It creates a sequence-like object that produces integers.
| Form | Values produced | Note |
|---|---|---|
range(4) | 0, 1, 2, 3 | start defaults to 0 |
range(2, 6) | 2, 3, 4, 5 | stop is excluded |
range(1, 8, 2) | 1, 3, 5, 7 | step is 2 |
range(5, 1, -1) | 5, 4, 3, 2 | counts down |
range(3, 3) | no values | empty range |
The stop value is never included. This is the source of many off-by-one exam mistakes.
Negative steps and empty ranges
A negative step moves downward. The start must be greater than the stop for the range to produce values.
print(list(range(5, 0, -2))) # [5, 3, 1]
print(list(range(0, 5, -1))) # []
The second range is empty because it starts at 0 and tries to move down while the stop is 5. It is already past the stopping boundary for a negative step. Also, range(1, 5, 0) is an error because the step cannot be zero.
Iterating over data
For loops can iterate directly over strings and lists:
letters = ['a', 'b', 'c']
word = ''
for letter in letters:
word += letter.upper()
print(word) # ABC
When indexes are needed, use range(len(data)):
items = [10, 20, 30]
for i in range(len(items)):
print(i, items[i])
The values of i are 0, 1, and 2. Do not confuse the index with the item. In for item in items, item is 10, then 20, then 30. In for i in range(len(items)), i is the position.
Trace-table method
Before solving a for-loop question, write the iteration list first:
| Source | Loop values |
|---|---|
range(2, 9, 3) | 2, 5, 8 |
'cat' | 'c', 'a', 't' |
[4, 1] | 4, 1 |
Then trace variables changed in the body:
| Iteration | i | total before | operation | total after |
|---|---|---|---|---|
| 1 | 2 | 0 | add 2 | 2 |
| 2 | 5 | 2 | add 5 | 7 |
| 3 | 8 | 7 | add 8 | 15 |
Loop variable after the loop
If a for loop runs at least once, the loop variable still exists after the loop and holds the last value assigned. After for n in range(3):, n is 2. If the loop never runs and the variable was not already defined, reading it afterward raises NameError. PCEP may use this to test whether you noticed an empty range.
Exam traps
Do not assume a loop runs because it is written. An empty range runs zero times. Do not include the stop value. Do not assume the loop variable resets automatically after the loop; if the loop ran, it still refers to the last assigned value. Finally, read whether the code iterates over values or indexes before deciding what gets printed.
What is printed by this code? total = 0 for n in range(1, 7, 2): total += n print(total)
Which range produces the values 6, 4, 2?
What is printed by this code? text = 'py' for ch in text: print(ch * 2, end='')