Know some Python? Write your own interactive tutorial, with runnable examples and exercises, and share it with a link. Write and share your own tutorial.

Start writing

Learn Python / For Loops

For Loops

Imagine printing a greeting for 100 students. Writing 100 print() lines would be painful. A loop runs the same block of code over and over, and a for loop runs it once for each item in a collection. The collection can be a list, a string, a dictionary, or a range of numbers.

Looping over a list

fruits = ["apple", "banana", "cherry"]

for fruit in fruits:
    print(f"I like {fruit}")

print("Done!")
Output

Here is what each part of the for line does:

Part Meaning
for Starts the loop.
fruit The loop variable. Python creates it for you; you don't assign it beforehand.
in fruits The collection to go through, one item at a time.
: Ends the for line. Forgetting it is a SyntaxError.
indented lines The body. These lines run once per item.

Python runs this loop in three passes, one per item:

  1. fruit is set to "apple", and the body prints I like apple.
  2. fruit is set to "banana", and the body prints I like banana.
  3. fruit is set to "cherry", and the body prints I like cherry.

There are no items left, so the loop ends and Python carries on with the first line that is not indented: print("Done!"), which runs only once. Indentation is how Python knows which lines belong to the loop. Use 4 spaces, the same as for if.

You can name the loop variable anything. Pick a name that describes one item, and name the list in the plural: for student in students, for price in prices.

Going deeper: After the loop, and empty lists optional

After the loop ends, the loop variable still holds the last item (cherry), and the list itself is unchanged. (pass is a statement that does nothing. Use it when Python needs a body but you have nothing to put there.)

fruits = ["apple", "banana", "cherry"]

for fruit in fruits:
    pass  # do nothing

print(fruit)
print(fruits)
Output

If the list is empty, the body runs zero times. That's not an error:

for fruit in []:
    print("This never prints")

print("The loop ran 0 times")
Output

Looping over a string

A string is a sequence of characters, so a for loop gives you one character at a time, from left to right:

for letter in "Python":
    print(letter)
Output

Every character counts, including spaces and punctuation. This loop counts the vowels in a sentence. len() reports 14 characters, because the two spaces, the comma and the ! count too, and the loop finds 4 vowels (i, e, e, a):

sentence = "Hi there, Sam!"

vowels = 0
for char in sentence:
    if char in "aeiouAEIOU":
        vowels += 1

print(len(sentence), "characters")
print(vowels, "vowels")
Output

range(): looping a number of times

range() produces a sequence of whole numbers for a loop to go through. It's how you repeat something a set number of times, or count through numbers. The simplest form takes one number, stop, and counts from 0 up to, but not including, stop:

for i in range(5):
    print("Lap", i)
Output

That prints Lap 0 to Lap 4: five laps, because range(5) gives exactly 5 numbers (0, 1, 2, 3, 4). It starts at 0 for the same reason list indexes do, so range(len(my_list)) gives every valid index of a list.

The three ways to call range()

range takes up to three numbers. The ones you leave out get a default value:

You write start stop step Numbers you get
range(5) 0 (default) 5 1 (default) 0, 1, 2, 3, 4
range(2, 6) 2 6 1 (default) 2, 3, 4, 5
range(0, 20, 5) 0 20 5 0, 5, 10, 15
range(10, 0, -2) 10 0 -2 10, 8, 6, 4, 2
  • start is the first number. It is included.
  • stop is where counting ends. It is never included: the numbers go up to it but stop just before.
  • step is how much to add each time. A negative step counts down.

A range doesn't show its numbers when you print it (print(range(5)) just prints range(0, 5)), so wrap it in list() to see them:

# 0 up to 5; 5 is left out
print(list(range(5)))

# start at 1, stop before 6
print(list(range(1, 6)))

# steps of 5; 20 is left out
print(list(range(0, 20, 5)))

# odd numbers: steps of 2
print(list(range(1, 10, 2)))

# count down; 0 is left out
print(list(range(10, 0, -2)))
print(list(range(5, 0, -1)))
Output

To include a number, make stop one past it. To count from 1 to 10, write range(1, 11); to count down to 1, stop at 0.

Here is range with a start in a real loop, printing part of a times table:

for n in range(1, 4):
    print(f"{n} x 7 = {n * 7}")
Output

When range() gives nothing

If step can't move from start towards stop, the range is empty and the loop body never runs. There's no error, which makes this an easy bug to miss:

# 5 can't count up to 1
print(list(range(5, 1)))

# 1 can't count down to 5
print(list(range(1, 5, -1)))

# start and stop are the same
print(list(range(3, 3)))
Output

To count down, you need both a start bigger than the stop and a negative step.

Going deeper: Two more range() rules optional
  • The numbers must be whole numbers (int). range(0, 1, 0.5) is an error.
  • step can't be 0. That would never reach stop, so Python refuses with an error.

When you only want to repeat something and don't need the number, it's common to name the loop variable _, which tells readers "I'm not using this":

for _ in range(3):
    print("Hip hip hooray!")
Output

Building up a result

A very common pattern: start with an empty or zero value, then update it on every pass.

prices = [4.99, 12.50, 3.25, 8.00]

total = 0
for price in prices:
    total += price

print(f"Total: {total:.2f}")
Output

Here's what happens to total on each pass through the loop:

Pass price total before total after
1 4.99 0 4.99
2 12.50 4.99 17.49
3 3.25 17.49 20.74
4 8.00 20.74 28.74

After the last pass, the loop ends and the print line runs once.

Two placement rules make this pattern work:

  • total = 0 goes before the loop. If you put it inside, it is reset to 0 on every pass, and at the end total only holds the last price.
  • print goes after the loop (not indented). Inside the loop, it would print a running total four times.

Try moving total = 0 into the loop body and run the code again to see the first mistake.

The same idea works for building a new list. Start with an empty list [] and append() to it on each pass. The original names list is left unchanged:

names = ["ada", "grace", "alan"]

capitalized = []
for name in names:
    capitalized.append(name.capitalize())

print(capitalized)
print(names)
Output

Using if inside a loop

Combine loops with if to filter or count. The if is indented once because it's inside the loop, and its own body is indented twice:

scores = [45, 82, 67, 91, 38, 74]

passed = 0
for score in scores:
    if score >= 50:
        passed += 1
        print(score, "pass")
    else:
        print(score, "fail")

print(f"{passed} of {len(scores)} passed")
Output

The if is checked separately on every pass: once for 45, once for 82, and so on. The final print isn't indented at all, so it runs once, after all six scores have been checked.

enumerate(): position and value together

When you need the position as well as the item, use enumerate(). On each pass it gives you a tuple (index, item), and you can unpack it into two variables right in the for line:

podium = ["Mia", "Leo", "Ava"]

# see the pairs enumerate() makes
print(list(enumerate(podium)))

for position, name in enumerate(podium, start=1):
    print(f"{position}. {name}")
Output
  • Counting starts at 0 by default, like list indexes.
  • start=1 makes it count from 1 instead, which is better for lists people read. It only changes the numbers you get; the list itself still starts at index 0.
  • for position, name in ... unpacks each pair, so position gets the number and name gets the item.

You may see loops like for i in range(len(podium)): followed by podium[i]. That works, but enumerate() is easier to read and harder to get wrong.

zip(): two lists side by side

zip() pairs up items from two (or more) lists by position: the first items together, then the second items, and so on. Each pair is a tuple you can unpack:

names = ["Ada", "Grace", "Alan"]
ages = [36, 85, 41]

# see the pairs zip() makes
print(list(zip(names, ages)))

for name, age in zip(names, ages):
    print(f"{name} is {age}")
Output

If the lists have different lengths, zip() stops at the end of the shortest one. Extra items in the longer list are skipped silently, without an error:

names = ["Ada", "Grace", "Alan"]
ages = [36, 85]

# Alan has no age, so he isn't printed
for name, age in zip(names, ages):
    print(name, age)
Output

Looping over a dictionary

Looping over a dictionary gives you its keys, in the order they were added. Use .values() for just the values, or .items() to get each key and value together as a pair:

stock = {"apples": 12, "pears": 0, "bananas": 7}

# the keys
for fruit in stock:
    print(fruit)

# the values
for count in stock.values():
    print(count)

# key and value together

for fruit, count in stock.items():
    if count == 0:
        print(f"{fruit}: SOLD OUT")
    else:
        print(f"{fruit}: {count} left")
Output
Loop over Each pass gives you
stock a key, such as "apples"
stock.values() a value, such as 12
stock.items() a (key, value) pair, such as ("apples", 12)

Counting words is a classic use of a loop plus a dictionary:

text = "the cat sat on the mat the end"

counts = {}
for word in text.split():
    counts[word] = counts.get(word, 0) + 1

print(counts)
Output

text.split() turns the sentence into a list of words. The key line is counts[word] = counts.get(word, 0) + 1:

  • counts.get(word, 0) gives the current count for word, or 0 if the word hasn't been seen yet. Plain counts[word] would crash with a KeyError the first time.
  • + 1 adds this occurrence, and the result is stored back under word.

So the first "the" stores 1, the second 2, and the third 3.

break and continue

break and continue change what happens on the current pass. You almost always use them inside an if:

Statement What it does
break Stops the loop immediately. Python skips any remaining items and jumps to the first line after the loop.
continue Skips the rest of this pass only. The loop carries on with the next item.

break is useful when you've found what you were looking for, or hit something that means "stop":

numbers = [3, 8, -1, 12, 5]

for n in numbers:
    if n < 0:
        print("Found a negative number, stopping.")
        break
    print(n)

print("After the loop")
Output

This prints 3 and 8, then the message. 12 and 5 are never looked at, because break ended the loop at -1.

continue is useful for skipping items you don't want to handle:

for n in range(1, 11):
    if n % 3 == 0:
        continue  # skip multiples of 3
    print(n, end=" ")
Output

For 3, 6 and 9, continue jumps straight to the next number, so print never runs for them. The output is 1 2 4 5 7 8 10. (end=" " makes print end with a space instead of a new line, so the numbers stay on one line.)

Going deeper: for ... else optional

A for loop can have an else block. It runs only when the loop finishes without hitting break. That makes it a neat fit for searches: did you find what you were looking for, or not?

numbers = [3, 7, 11, 15]

for n in numbers:
    if n % 2 == 0:
        print("Found an even number:", n)
        break
else:
    print("No even numbers in the list")
Output

Change one of the numbers to an even number and run it again. This time break happens, so the else block is skipped.

Without else, you'd need an extra variable to remember whether you found something:

numbers = [3, 7, 11, 15]
found = False

for n in numbers:
    if n % 2 == 0:
        found = True
        break

if not found:
    print("No even numbers in the list")
Output

The easiest way to read it is as "no break". The else doesn't mean "if the loop didn't run": looping over an empty list also runs the else block, because nothing called break.

Going deeper: Loops inside loops optional

A loop can contain another loop. The inner loop runs completely for each pass of the outer loop:

for row in range(1, 4):
    for col in range(1, 4):
        print(row * col, end="\t")
    print()   # new line after each row
Output

The outer loop runs 3 times, and each time the inner loop runs 3 times, so the inner body runs 3 × 3 = 9 times. "\t" is a tab, which lines the numbers up in columns. A break inside the inner loop only stops the inner loop; the outer loop carries on with its next pass.

Going deeper: Don't change a list while looping over it optional

Removing items from a list while a for loop is going through it makes the loop skip items. Here the second 3 survives:

numbers = [1, 3, 3, 4, 5]

for n in numbers:
    if n == 3:
        numbers.remove(n)

print(numbers)  # one 3 was skipped!
Output

When the first 3 is removed, every later item shifts one place to the left, so the loop jumps straight past the second 3. The safe way is to build a new list with the items you want to keep:

numbers = [1, 3, 3, 4, 5]
kept = []

for n in numbers:
    if n != 3:
        kept.append(n)

print(kept)
Output

You'll learn a shorter way to write this in the List Comprehensions lesson.

Exercises

Exercise 1: Countdown

Use a for loop and range() to print 5, 4, 3, 2, 1 on separate lines, then Liftoff!.

# Count down from 5
Output

Exercise 2: Sum of even numbers

Add up all the even numbers from 1 to 100 (inclusive) and print the total, which is 2550.

total = 0
Output

Exercise 3: Longest word

Find and print the longest word in the list without using max(). It should print elephant.

words = ["cat", "elephant", "dog", "giraffe", "ant"]
Output

Exercise 4: Shopping receipt

Print each item with its line total, then the grand total. Use .items() to loop over the dictionary.

coffee x 2 = 6.0
muffin x 3 = 7.5
juice x 1 = 4.0
Total: 17.5
prices = {"coffee": 3.0, "muffin": 2.5, "juice": 4.0}
cart = {"coffee": 2, "muffin": 3, "juice": 1}
Output

Summary

  • for item in collection: runs the indented body once for each item. The first unindented line after it runs once, when the loop is done.
  • range(stop), range(start, stop) and range(start, stop, step) produce whole numbers. start defaults to 0 and step to 1. start is included and stop never is, so use range(1, 11) for 1 to 10.
  • A negative step counts down (range(5, 0, -1)). If the step can't reach stop, the range is empty and the loop doesn't run.
  • Build results with a variable set before the loop and updated inside it (total += x, or append to a list).
  • enumerate() gives (index, item) pairs (add start=1 to count from 1). zip() pairs up lists and stops at the shortest.
  • Looping over a dictionary gives its keys. Use .values() for values and .items() for (key, value) pairs.
  • break exits the loop at once, and continue skips to the next pass.

Share this tutorial

Know something worth teaching? Write your own tutorial with runnable examples and share it.