◐ ai-teacher

🐍 Python for Data Engineers · Chapter 2

Control flow: if, for, while

Three shapes — ask a question, repeat over things, repeat until something changes. Every program you will ever write is these three arranged.

Study this lesson free in the app →

The basics

Control flow is how a program decides which lines run and how many times. Without it, code runs top to bottom exactly once. With it, you can make decisions and repeat work over a million rows.

The problem it solves: real data is uneven — some rides are cancelled, some fares are negative, some API responses have another page. You need to ask questions and repeat steps without writing the same line a thousand times.

The mental model: a parcel sorter at a conveyor belt. Three shapes, and every program is these three nested:

Words you must know 4

continue
skip the rest of this pass, move to the next item.
break
stop the loop entirely; everything after is skipped.
Accumulator
a variable set before the loop (total = 0) and built up inside it.
Indentation
four spaces. It is the syntax: it decides what is inside the loop and what runs once after it.

The production habit: skip a bad row, but record that you skipped it.

Explained

if fare > 500:            # ask a question
    band = "high"

for event in events:      # do this to each thing
    process(event)

while cursor:             # keep going until something changes
    page = fetch(cursor)

That's it. Everything else is these three, nested and named.

The parcel sorter

A sorter stands at a conveyor belt.

for — they handle every parcel that arrives. The belt decides how many; the sorter doesn't count. When the belt is empty, they stop.

if — for each parcel they ask a question. Heavy? Left chute. Fragile? Right chute. Otherwise, straight on.

while — a different job: keep collecting parcels until the trolley is full. Nobody knows in advance how many that is. The condition, not the belt, decides when to stop.

The distinction matters: for when you know the collection, while when you know the condition. Choose wrong and you either write awkward code or hang forever.

The shapes, written out

# ---- if / elif / else ----
if fare > 500:
    band = "high"
elif fare > 100:          # only checked if the first was False
    band = "mid"
else:
    band = "low"

# combining conditions
if status == "completed" and fare > 0:
    ...
if city in ("Shillong", "Guwahati"):     # 'in' beats three ors
    ...
if not events:                            # empty list is falsy
    return

# ---- for ----
for event in events:
    print(event)

for i, event in enumerate(events, start=1):   # need the position too
    print(i, event)

for city, revenue in totals.items():          # walking a dict
    print(city, revenue)

for n in range(5):        # 0,1,2,3,4 — a count, not a collection
    ...

# ---- while ----
cursor = None
while True:
    page = fetch(cursor)
    yield from page["data"]
    cursor = page.get("next")
    if not cursor:
        break             # the only exit — make it obvious

Step through a loop with a skip

continue = skip this one. break = stop entirely. Confusing them is a classic beginner bug — and one that silently loses data.

Two loops, one difference

# version A
for e in events:
    if e["fare"] < 0:
        break
    total += e["fare"]

# version B
for e in events:
    if e["fare"] < 0:
        continue
    total += e["fare"]

The list has 1,000 events. Event number 3 has a negative fare (a refund that was written wrongly).

Indentation is the syntax

Other languages use { }. Python uses indentation, and it is not decoration — it is how the language knows what's inside what.

for e in events:
    total += e.fare      # inside the loop — runs every pass
print(total)             # outside — runs once

for e in events:
    total += e.fare
    print(total)         # inside — prints on EVERY pass

Those two are different programs. On a million events, the second prints a million lines.

Rules that avoid all indentation pain:

Gotchas

for when you know the collection. while when you know the condition.

continue = skip this one. break = stop everything.

Indentation is the structure. Four spaces, always.

Words to know

Conditionalif / elif / else — choosing a branch based on a test.
IterationRepeating an action across the items of a collection.
for loopRepeats once per item in a collection; the collection decides the count.
while loopRepeats until its condition becomes false; the condition decides the count.
breakExits the loop entirely, skipping all remaining items.
continueSkips the rest of the current pass and moves to the next item.
enumerateYields (index, item) pairs so you get the position without a counter.
AccumulatorA variable declared before a loop that builds up a result inside it.

In two minutes

Test yourself

1. A bad row appears at position 3 of 1000 and your loop calls break. What happens?

  1. That row is skipped, 999 processed
  2. The loop stops — 997 good rows are silently discarded
  3. An exception is raised
  4. The loop restarts
Show the answer

The loop stops — 997 good rows are silently discarded — break exits entirely. It's the dangerous one because the data loss is silent and depends on where the bad row happens to sit.

2. Where must total = 0 go?

  1. Inside the loop
  2. Before the loop
  3. After the loop
  4. It doesn't matter
Show the answer

Before the loop — Inside the loop it resets on every pass, so you end up with only the last item's value — a bug that looks like bad data.

3. You need the position of each item as well as the item. Use…

  1. range(len(x))
  2. enumerate(x)
  3. while
  4. x.index()
Show the answer

enumerate(x) — enumerate gives (index, item) directly. range(len(x)) works but is noisier, and x.index() inside a loop is O(n²).

4. Why is an infinite while loop worse than a crash?

  1. It uses more memory
  2. The job hangs with no failure signal, so nothing alerts
  3. It corrupts data
  4. It is slower to debug
Show the answer

The job hangs with no failure signal, so nothing alerts — A crash produces a stack trace and a failed run. A hang produces nothing — the run sits in 'running' and blocks the schedule.

5. What does list(range(2, 10, 3)) produce?

  1. [2, 5, 8]
  2. [2, 5, 8, 11]
  3. [3, 6, 9]
  4. [2, 3, 4, 5, 6, 7, 8, 9]
Show the answer

[2, 5, 8] — range(start, stop, step): start at 2, add 3 each time, and stop before 10. 11 would be past the stop value.

6. You're paging through an API that returns a next cursor until there are no more pages. You don't know how many pages exist. Which loop fits?

  1. for page in range(100)
  2. a for loop over a list of pages
  3. while — continue until the cursor is empty
  4. No loop — call it once
Show the answer

while — continue until the cursor is empty — You know the stopping condition, not the count. range(100) either stops early or wastes calls; a while with a clear break on an empty cursor matches the problem.

There are 10 questions, 3 puzzles and 5 recall cards for this lesson in the app — the recall cards come back on later days, just before you would forget.

Learn it so it stays. Read it, test yourself, then recall it on two different days. The app schedules that for you, free.

Start this lesson →