Index Ai Academy
Phase 0 · Tools · Python core

Loops

Repeat work over every item without copy-pasting code.

About 25 minutes · Free lesson

Start this lesson

Why it matters

AI work is repetitive in exactly the way computers are good at. Score 500 headlines. Send 20 prompts and compare the answers. Process every row of an export. Run a test over a whole set of examples. When you train a neural network in Phase 4, the training itself is a loop that runs thousands of times. Loops let you say "do this for each one" once, instead of copying code.

What you'll be able to do

  • Repeat code for every item in a list with a for loop
  • Use the accumulator pattern to total, count and track the best item
  • Filter items into a new list with if inside a loop
  • Use range, enumerate, zip, while, break and continue

What it covers

  1. Do something for every item
  2. The accumulator pattern
  3. Looping over rows
  4. while: repeat until something changes
  5. Worked example: a week of ad results
  6. Reading a loop by hand
  7. Name what you're looping over

Do something for every item

Think of stuffing envelopes for a mailing: take the next letter, fold it, put it in, seal it, repeat until the pile is gone. A for loop is that. It runs a block of code once for each item in a list:

channels = ["search", "display", "email"]

for channel in channels:
    print("Checking", channel)

print("Done")
It runs right here in your browser, with nothing to install.

Read it as "for each channel in channels, do the indented block". Each pass through the loop is called an iteration. On each one, the variable channel holds the next item. You choose its name: pick the singular of the list's name, so the code reads naturally.

The block follows the same indenting rules as if. The unindented print("Done") runs once, after the loop finishes.

A loop works on a string too, one character at a time.

Try it now

Watch spend take each value in turn while total grows. The loop body (line 4) runs four times, then Python moves on to the print.

The accumulator pattern

That stepper shows the most common loop shape there is:

  1. Before the loop, create a variable with a starting value: 0 for a total or a count, [] for a list you'll fill.
  2. Inside the loop, update it using the current item.
  3. After the loop, use the result.

Combined with if, the same shape counts, filters and finds the best item:

ctrs = [0.031, 0.012, 0.044, 0.019, 0.027]

count_strong = 0
weak = []
best = 0

for ctr in ctrs:
    if ctr >= 0.025:
        count_strong += 1
    else:
        weak.append(ctr)
    if ctr > best:
        best = ctr

print("Strong:", count_strong)
print("Weak:", weak)
print("Best:", best)

Python also has sum() and max() built in, and for a plain total you'd use them. The pattern matters for everything they can't do. Counting only some items. Collecting the names that failed a check. Or tracking the best item's name, not just its value.

Quick check
What does this print?
count = 0
for word in ["sale", "SALE", "Sale", "deal"]:
    if word.lower() == "sale":
        count += 1
print(count)
  1. 1
  2. 3
  3. 4
  4. 0
Show the answer

3

Lowercasing makes "sale", "SALE" and "Sale" all equal to "sale", so count goes up three times, and "deal" adds nothing. It ends at 3.

Looping over rows

Sometimes each item is itself a list, such as a row with a name and some numbers. Then you can unpack it straight into separate variables in the for line:

campaigns = [
    ["Spring Sale", 5000, 3120.5],
    ["Retargeting", 2000, 2150.0],
    ["Newsletter", 500, 120.0],
]

for name, budget, spend in campaigns:
    remaining = budget - spend
    print(f"{name}: {remaining:,.2f} left")

The number of names before in must match the length of each row.

Counting with range, numbering with enumerate, pairing with zip

range() produces a sequence of whole numbers to loop over:

  • range(5) is 0 up to, but not including, 5.
  • range(1, 6) starts at 1.
  • range(0, 100, 25) counts in steps of 25.
for week in range(1, 4):
    print("Week", week)

print(list(range(0, 100, 25)))   # list() shows the numbers range produces

enumerate() gives you a position number alongside each item, and zip() walks through two lists side by side:

headlines = ["Spring sale", "New arrivals", "Last chance"]
for number, headline in enumerate(headlines, start=1):
    print(f"{number}. {headline}")

names = ["Search", "Display", "Email"]
spends = [3120.5, 1890, 120]
for name, spend in zip(names, spends):
    print(f"{name}: {spend:,.2f}")

while: repeat until something changes

A while loop repeats as long as its condition stays True. It's like stirring until the sauce thickens: you don't know how many stirs it'll take. Use it when you don't know in advance how many repeats you need:

budget = 1000
weeks = 0
while budget < 5000:
    budget = budget * 1.4      # grow 40% a week
    weeks += 1
print(weeks, "weeks to pass 5000; budget is now", round(budget))

Something inside the loop must eventually make the condition False. If nothing does, the loop runs forever. That's called an infinite loop. The academy stops your code after a few seconds if you write one by accident.

break and continue

break leaves the loop straight away. continue skips the rest of the current iteration and moves on to the next item.

campaigns = [["Search", 5000, 3120.5], ["Display", 2000, 2150], ["Email", 500, 620]]

for name, budget, spend in campaigns:
    if spend > budget:
        print("First campaign over budget:", name)
        break

emails = ["ana@shop.com", "", "ben@shop.com", "   ", "cy@shop.com"]
sent = 0
for email in emails:
    if email.strip() == "":
        continue               # skip blanks
    sent += 1
print("Sent to", sent, "addresses")

break stopped at Display, so Email was never checked, even though it's also over budget.

Quick check
What does this print?
total = 0
for n in range(1, 4):
    total += n
print(total)
  1. 3
  2. 6
  3. 4
  4. 10
Show the answer

6

range(1, 4) gives 1, 2 and 3 (it stops before 4). Adding them up: 1 + 2 + 3 = 6.

Worked example

Worked example: a week of ad results

Each row is a headline, its impressions and its clicks. In one pass, total the clicks, find the headline with the best click-through rate, and list every headline under 2%.

ads = [
    ["Headline A", 12000, 360],
    ["Headline B", 9500, 180],
    ["Headline C", 15000, 600],
    ["Headline D", 4000, 40],
]

total_clicks = 0
best_name = ""
best_ctr = 0
weak = []

for name, impressions, clicks in ads:
    ctr = clicks / impressions
    total_clicks += clicks
    if ctr > best_ctr:
        best_ctr = ctr
        best_name = name
    if ctr < 0.02:
        weak.append(name)

print(f"Total clicks: {total_clicks:,}")
print(f"Best: {best_name} ({best_ctr:.1%})")
print(f"Under 2% CTR: {weak}")
In the lesson you can change this and run it.

Four accumulators share one loop: a running total, the best value so far, the name that goes with it, and a list of names that fail a check. Notice that best_ctr and best_name are updated together inside the same if, so they always describe the same headline. The two if statements are separate (not if/elif) because a headline could, in principle, be both the best and weak, and each check must run independently.

Quick check
How many times does the body of for i in range(4): run?
  1. It depends on i
  2. 5
  3. 4
  4. 3
Show the answer

4

range(4) produces 0, 1, 2 and 3: four numbers, so four iterations.

Reading a loop by hand

When a loop gives the wrong answer, don't stare at it. Play computer with a pencil. Write each variable as a column, and fill in one row for each time through.

For total = 0, then for n in [2, 5, 3]: total += n:

ntotal after this pass
22
57
310

It takes a minute, and it shows exactly where your idea and the code part ways. The step-through view earlier in this lesson does the same thing automatically.

Four bugs you'll write at least once

Forgetting to add. total = n replaces the total on each pass, so you end up with the last number. You wanted total += n.

Starting in the wrong place. If total = 0 sits inside the loop, the total resets on every pass. Starting values go above the loop.

Printing in the wrong place. A print indented inside the loop runs on every pass. If you want one final answer, move it back to the left, level with for.

A while that never ends. A while loop stops only when its condition turns false, so something inside must change it. If nothing does, the program runs forever. In the browser, the run limit stops it. On your own computer, press Ctrl+C.

Remember, too, that range(5) means 0, 1, 2, 3 and 4. It starts at 0 and stops before 5. If you want 1 to 5, write range(1, 6).

Name what you're looping over

Plural for the list and singular for the item, as in for price in prices, makes loops much easier to read later.

Practice what you just read

  • 8 code examples you can edit and run
  • a practice exercise that checks your code
  • a 6-question quiz
  • 6 review cards for spaced repetition

Start this lesson

Try a quiz question

What does this print?

total = 0
for n in [4, 6, 10]:
    total = n
print(total)
  1. 10
  2. 20
  3. 4
  4. 0

Answer it at the end of the lesson to see if you're right, and why.

Before this lesson