← back to section

Sampling is a compromise: you looked at five records out of five hundred and hope the rest are the same. A loop removes the compromise: checking all five hundred costs the same as checking one.

A loop over a list

live example

statuses = ["NEW", "PAID", "SHIPPED"]

for status in statuses:
    print(status)
Run

Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Free week →

It reads literally: "for each status in statuses — print the status". You do not declare the variable beforehand; the loop does it, putting the next element in on every pass.

The loop body is indented, like an if. Everything indented repeats; everything not indented runs once, after the loop.

Accumulating a sum and a counter

live example

items = [
    {"product": "Grinder", "qty": 1, "price": 4990},
    {"product": "Lunchbox", "qty": 2, "price": 890},
]

total = 0
for item in items:
    total = total + item["qty"] * item["price"]

print(total)     # 6770
Run

Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Free week →

The accumulator is declared before the loop and set to zero — otherwise it would reset on every pass. total = total + x is usually shortened to total += x.

A counter is the same thing with one added:

cancelled = 0
for order in orders:
    if order["status"] == "CANCELLED":
        cancelled += 1

Note the double indent: the if sits inside the for, and its body is further right still. Indents show nesting.

A loop over a dict

live example

order = {"id": "ord-042", "status": "PAID", "total": 4990}

for key in order:
    print(key)                       # id, status, total

for key, value in order.items():
    print(f"{key} = {value}")
Run

Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Free week →

items() hands out pairs, unpacked into two variables at once. Handy when you need to check the whole response — for example, that no field is empty.

Stopping early

for order in orders:
    if order["id"] == wanted:
        found = order
        break          # no point searching further

break leaves the loop, continue skips the current pass:

for order in orders:
    if order["status"] == "DRAFT":
        continue       # drafts do not count
    ...

Building a new list

ids = []
for order in orders:
    ids.append(order["id"])

Python has a short form of the same thing — worth recognising in other people's code:

ids = [order["id"] for order in orders]
cancelled = [o for o in orders if o["status"] == "CANCELLED"]

This is a list comprehension. Write whichever is clearer: the long form is more readable, the short one more compact.

Common mistakes

The accumulator inside the loop. total = 0 ends up indented — the sum resets every pass and the last value survives.

Modifying a list while iterating it. Removing elements from the list you are walking skips items. Build a new list and replace the old one.

Wrong indent. A line that should be inside the loop ends up outside and runs once instead of a hundred times. No error, wrong result; print intermediate values to see it.

What to solve

In short

  • for item in items walks every element; no need to declare the variable.
  • The accumulator (total = 0) is declared before the loop, or it resets.
  • Walk a dict through .items() — key and value at once.
  • break leaves the loop, continue skips a pass.
  • A comprehension [o["id"] for o in orders] is the same work in short form.