The for loop

A for loop repeats a block once for each item in a sequence — a list, string, range, dictionary, file, anything iterable:

for fruit in ["apple", "kiwi", "pear"]:
    print("I like", fruit)

for ch in "abc":
    print(ch.upper(), end=" ")
print()
I like apple I like kiwi I like pear A B C

Unlike C-style languages there is no counter to manage; Python hands you each item in turn.

range()

When you need numbers, range(start, stop, step) generates them lazily. stop is exclusive:

for i in range(5):        print(i, end=" ")   # 0..4
print()
for i in range(2, 7):     print(i, end=" ")   # 2..6
print()
for i in range(10, 0, -3): print(i, end=" ")  # 10 7 4 1
print()
print(list(range(0, 20, 5)))
0 1 2 3 4 2 3 4 5 6 10 7 4 1 [0, 5, 10, 15]

enumerate() and zip()

Need the index as well as the item? Use enumerate. Walking two lists side by side? Use zip:

names = ["Ada", "Linus", "Grace"]
langs = ["Analytical Engine", "Linux", "COBOL"]

for i, name in enumerate(names, start=1):
    print(f"{i}. {name}")

for name, lang in zip(names, langs):
    print(f"{name} -> {lang}")
1. Ada 2. Linus 3. Grace Ada -> Analytical Engine Linus -> Linux Grace -> COBOL

The while loop

while repeats as long as a condition stays true. Use it when you do not know in advance how many iterations you need:

import random
secret = random.randint(1, 10)
guess = None
tries = 0
while guess != secret:
    guess = int(input("Guess 1-10: "))
    tries += 1
print(f"Correct! It took {tries} tries.")
Guess 1-10: 5 Guess 1-10: 8 Correct! It took 2 tries.

Every while loop needs something inside it that eventually makes the condition false, otherwise it runs forever. If that happens on the phone, tap the stop button in the console.

break, continue and else

for n in range(2, 20):
    if n % 7 == 0:
        print("First multiple of 7:", n)
        break            # leave the loop entirely

for n in range(1, 8):
    if n % 2 == 0:
        continue         # skip to the next iteration
    print(n, end=" ")
print()

for n in [3, 5, 9]:
    if n % 2 == 0:
        print("Found an even number")
        break
else:
    print("No even numbers")   # runs only if loop was NOT broken
First multiple of 7: 7 1 3 5 7 No even numbers

The else on a loop trips people up: think of it as "no break happened".

Nested loops

for row in range(1, 4):
    for col in range(1, 4):
        print(f"{row * col:3}", end="")
    print()
1 2 3 2 4 6 3 6 9

Nested loops multiply work: two loops of 1,000 iterations run one million times. That is fine for learning, but keep it in mind when data gets big.

Run the loops in the app's built-in FizzBuzz example — the Coding Python app runs real Python 3 on your phone, with examples, quizzes and challenges built in.
Get it free

Generators: making your own iterable

Everything above loops over something that already exists. A generator produces values on demand instead: write yield where you would have appended to a list, and the function hands back one value at a time, remembering where it left off.

def countdown(n):
    while n > 0:
        yield n
        n = n - 1

for x in countdown(3):
    print(x)
3 2 1

Nothing runs until you iterate, and only one value exists at a time. That is what makes a generator able to describe a sequence too large to hold in memory — or one with no end at all:

import itertools

def naturals():
    n = 1
    while True:
        yield n
        n = n + 1

print(list(itertools.islice(naturals(), 5)))
[1, 2, 3, 4, 5]

A generator expression is the same idea in one line — a comprehension with round brackets. Use it when you only want to consume the values once:

nums = [1, 2, 3, 4, 5]

total = sum(n * n for n in nums)   # no list is built
print(total)
55

The rule of thumb: build a list when you need to keep the values, index them or go through them more than once; use a generator when you are passing straight through. yield from delegates to another generator, which is how pipelines are chained together.

Exercise: FizzBuzz

Print the numbers 1 to 30, but print "Fizz" for multiples of 3, "Buzz" for multiples of 5 and "FizzBuzz" for both. This is the classic interview warm-up and one of the 30 built-in examples in the Coding Python app.

for n in range(1, 31):
    if n % 15 == 0:
        print("FizzBuzz")
    elif n % 3 == 0:
        print("Fizz")
    elif n % 5 == 0:
        print("Buzz")
    else:
        print(n)
1 2 Fizz 4 Buzz Fizz 7 ...

Loops and lists go together, so Python lists are next.

🏭
Practise this: Loop Factory

Make the conveyor produce exactly these lines — 6 levels that run real Python in your browser.

Play free
🚰
Practise this: Pipeline

Produce values one at a time, not all at once — 6 levels that run real Python in your browser.

Play free

Frequently asked questions

What is the difference between a for loop and a while loop?

A for loop iterates over a known sequence of items; a while loop repeats until a condition becomes false. Use for when you know what you are looping over, while when you are waiting for something to happen.

How do I loop with an index in Python?

Use enumerate(): for i, item in enumerate(items). Avoid range(len(items)) unless you genuinely need only the index.

How do I stop an infinite loop?

Make sure the loop body changes the condition, or use break. In the Coding Python app, tap the stop button in the console to kill a runaway program.

What does the else clause on a loop do?

It runs once after the loop finishes normally, but is skipped if the loop ended via break. It is useful for 'searched everything and found nothing' logic.

What is the difference between a generator and a list?

A list holds every value in memory at once; a generator produces them one at a time and remembers its place. Use a list when you need to keep, index or re-read the values, and a generator when you pass through once.

What does yield do in Python?

It hands one value back to whoever is iterating and pauses the function, keeping its local variables. The next time round, the function resumes from just after the yield.