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:

  • while repeats as long as a condition holds. Use it when you do not know in advance how many rounds you need.
  • for repeats 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) — from 0 up to stop;
  • range(start, stop) — from start up to stop;
  • range(start, stop, step) — from start, in steps of step.

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 while loop, 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.