Loops
Repeating work with for and while, counting with range(), and steering a loop with break, continue and else.
What a loop is
Computers are good at doing the same thing many times. A loop is a statement that runs its block repeatedly, so you write the work once instead of copying it. One run through the block is called an iteration; "the loop iterates over a list" means it takes the items one at a time.
Python has two loop statements:
-
whilerepeats as long as a condition holds. Use it when you do not know in advance how many rounds you need. -
forrepeats once for each item of a collection or other series of values. Use it when you have something to walk through.
Both use a colon and an indented
block, just
like if.
while loops
A while loop checks its condition before every round.
If the condition is true, the block runs and Python goes back to the
top to check again. As soon as the condition is false, the loop ends
and the program continues after it. If the condition is false the
very first time, the block never runs.
countdown = 3
while countdown > 0:
print(countdown)
countdown -= 1
print("Liftoff!")
3 2 1 Liftoff!
Something inside the block must eventually make the condition false
— here, countdown -= 1. A typical use is reading input
until the user signals they are done:
total = 0
entry = input("Price (empty to stop): ")
while entry != "":
total += float(entry)
entry = input("Price (empty to stop): ")
print("Total:", total)
Price (empty to stop): 2.50 Price (empty to stop): 4.25 Price (empty to stop): Total: 6.75
Infinite loops
An infinite loop is a loop whose condition never becomes false, so it never ends on its own. Usually that is a bug — forgetting to update the variable in the condition is the classic cause:
count = 1
while count <= 5:
print(count) # prints 1 forever: count never changes
To stop a program stuck in a loop, press
Ctrl+C in the terminal. Python raises a
KeyboardInterrupt exception and stops, showing where it
was.
An infinite loop can also be deliberate:
while True: runs until a
break
inside it ends the loop. This is handy when the exit test fits best
in the middle of the block rather than at the top.
savings = 1000
years = 0
while True:
savings = savings * 1.05
years += 1
if savings >= 1500:
break
print(years, "years:", round(savings, 2))
9 years: 1551.33
for loops
A for loop takes the items of a series one by one,
assigns each to a variable — the loop variable — and runs
the block for it. When there are no items left, the loop ends. You
do not manage a counter or a condition yourself.
cities = ["Lisbon", "Oslo", "Tokyo"]
for city in cities:
print("Flight to", city)
Flight to Lisbon Flight to Oslo Flight to Tokyo
Anything a for loop can walk through is called an
iterable: an object that can hand
out its items one at a time. Lists, tuples, strings, dictionaries,
sets, files and range() are all iterables. A number is
not: for x in 5: raises a TypeError.
Iterating over strings, lists and dictionaries
What a loop receives depends on the iterable. A string gives its
characters; a list or tuple gives its items in order; a dictionary
gives its keys. To get keys and values together, loop over
.items() — see
Dictionaries and Sets.
for letter in "Oslo":
print(letter, end=" ")
print()
prices = {"coffee": 2.5, "tea": 2.0}
for item in prices:
print(item)
for item, price in prices.items():
print(item, "costs", price)
O s l o coffee tea coffee costs 2.5 tea costs 2.0
Modifying a list while iterating
Do not add items to, or remove items from, a list while a
for loop walks through that same list. The loop keeps
track of its position by index; when you remove an item, everything
after it shifts one place to the left, and the loop skips the item
that moved into the current position.
readings = [12, -1, -3, 15, -2, 18]
for value in readings:
if value < 0:
readings.remove(value)
print(readings) # -3 survived!
[12, -3, 15, 18]
After -1 is removed, -3 moves into its
place and the loop continues with the next position, so
-3 is never checked. The safe way is to build a new
list (or loop over a copy, readings[:]):
readings = [12, -1, -3, 15, -2, 18]
valid = []
for value in readings:
if value >= 0:
valid.append(value)
print(valid)
[12, 15, 18]
A list comprehension does the same
in one line. Changing a dictionary's size during iteration is even
stricter: Python stops with a RuntimeError.
Counting with range()
To repeat something a number of times, or to walk through numbers,
loop over a range. The built-in
range() produces a series
of whole numbers, and it takes one, two or three arguments:
-
range(stop)— from0up tostop; -
range(start, stop)— fromstartup tostop; -
range(start, stop, step)— fromstart, in steps ofstep.
The stop value itself is
never included. A negative step counts
down; then start must be larger than stop.
When the start is already "past" the stop, the range is simply empty
and the loop body never runs. list() shows the numbers:
print(list(range(5)))
print(list(range(2, 6)))
print(list(range(0, 20, 5)))
print(list(range(10, 0, -3)))
print(list(range(5, 1))) # empty: start is past stop
print(list(range(1, 5, -1))) # empty: counting down from 1 never reaches 5
print(len(range(0, 20, 5)))
[0, 1, 2, 3, 4] [2, 3, 4, 5] [0, 5, 10, 15] [10, 7, 4, 1] [] [] 4
A range does not store all its numbers; it computes
each one when it is needed, so
range(1_000_000_000) takes almost no memory. The
arguments must be integers, and a step of 0 raises a
ValueError.
for i in range(3):
print("Attempt", i + 1)
Attempt 1 Attempt 2 Attempt 3
break and continue
Two statements change the normal course of a loop, in both
for and while:
- The break statement ends the loop immediately. Python continues with the first statement after the loop.
-
The continue statement
ends only the current iteration. The rest of the block is skipped
and the loop goes on with the next item (or, in a
whileloop, with the next check of the condition).
temperatures = [18, 21, 25, 31, 28]
for t in temperatures:
if t > 30:
print("Heat warning:", t)
break
print("OK:", t)
OK: 18 OK: 21 OK: 25 Heat warning: 31
for n in range(1, 8):
if n % 3 == 0:
continue # skip multiples of 3
print(n, end=" ")
print()
1 2 4 5 7
The else clause on loops
Both loops can have an else clause. Its block runs
once, when the loop finishes normally: a
for loop that ran out of items, or a
while loop whose condition became false. If the loop is
ended by break, the else block is skipped.
That makes it a neat fit for searching: break when you
find what you are looking for, and let else handle "not
found" — without an extra flag variable.
guests = ["Ada", "Grace", "Linus"]
for name in guests:
if name == "Alan":
print("Alan is on the list.")
break
else:
print("Alan is not on the list.")
Alan is not on the list.
n = 29
divisor = 2
while divisor * divisor <= n:
if n % divisor == 0:
print(n, "is divisible by", divisor)
break
divisor += 1
else:
print(n, "is prime")
29 is prime
for i in range(0):
print("never printed")
else:
print("else runs anyway")
else runs anyway
Nested loops
A loop inside another loop is a nested loop. For each round of the outer loop, the inner loop runs completely. An outer loop of 3 rounds with an inner loop of 3 rounds therefore runs the inner block 3 × 3 = 9 times. Nested loops are the natural way to walk through rows and columns:
for row in range(1, 4):
for col in range(1, 4):
print(f"{row * col:4}", end="")
print() # new line after each row
1 2 3 2 4 6 3 6 9
break and continue only affect the
innermost loop they are in. A break in the inner loop
ends that inner loop; the outer loop carries on with its next round.
shelves = [["tea", "coffee"], ["soap", "EMPTY", "towels"], ["rice"]]
for shelf in shelves:
for product in shelf:
if product == "EMPTY":
break # stops this shelf only
print(product, end=" ")
print("|")
tea coffee | soap | rice |
enumerate() and zip()
Two built-in functions make common for loops shorter
and clearer.
enumerate(iterable) gives pairs of
(position, item), so you get a counter without managing one
yourself. It starts at 0; pass start=1 for human
numbering. Prefer it to for i in range(len(items)).
tasks = ["backup", "update", "reboot"]
for number, task in enumerate(tasks, start=1):
print(number, task)
1 backup 2 update 3 reboot
zip(a, b, …) walks through several iterables at the
same time and gives one tuple per step, with one item from each. It
stops as soon as the shortest iterable runs out; extra
items in the longer ones are silently ignored. (Since Python 3.10,
zip(a, b, strict=True) raises a
ValueError instead when the lengths differ.)
names = ["Ada", "Grace", "Linus"]
scores = [92, 88, 75, 60]
for name, score in zip(names, scores):
print(name, score)
Ada 92 Grace 88 Linus 75
The number, task and name, score parts are
tuple unpacking: each pair is split into two variables. See
packing and unpacking.