🐍 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:
if— ask a question about each parcel; pick a chute.elifis only checked if everything above was false.for— handle every parcel on the belt. The collection decides how many times.while— keep going until a condition changes (trolley full, no next page). The condition decides — so it must be able to become false.
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 obviousStep 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 passThose two are different programs. On a million events, the second prints a million lines.
Rules that avoid all indentation pain:
- Four spaces per level. Not tabs, not two, not eight
- Let your editor insert spaces when you press Tab
- A line ending in
:is always followed by an indented block - If a block feels too deeply nested (three levels or more), that's a signal to extract a function — which is the next lesson
Gotchas
breakwhere you meantcontinue— silently drops the rest of the data- Accumulator inside the loop —
total = 0on the wrong line resets it every pass, so you end up with only the last value - Modifying a list while looping over it — elements get skipped. Build a new list instead
whilewith no way to become false — the job hangs forever, and a hang is worse than a crash because nothing alertsif x == True— just writeif x. And forNone, writeis Noneelseon aforloop — real Python, runs only if the loop wasn't broken out of. Almost nobody knows it; avoid it in shared code
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
| Conditional | if / elif / else — choosing a branch based on a test. |
|---|---|
| Iteration | Repeating an action across the items of a collection. |
| for loop | Repeats once per item in a collection; the collection decides the count. |
| while loop | Repeats until its condition becomes false; the condition decides the count. |
| break | Exits the loop entirely, skipping all remaining items. |
| continue | Skips the rest of the current pass and moves to the next item. |
| enumerate | Yields (index, item) pairs so you get the position without a counter. |
| Accumulator | A variable declared before a loop that builds up a result inside it. |
In two minutes
- Three shapes: if asks, for repeats over a collection, while repeats until a condition changes.
- if/elif/else checks top to bottom and runs only the first true branch — order conditions from most specific.
- Use for when you know the collection, while when you know the stopping condition; a while must be able to end.
- continue skips one item; break abandons the rest of the loop — confusing them silently loses data.
- Accumulators go before the loop; inside they reset every pass.
- Indentation is syntax: four spaces decide what runs per item and what runs once.
- Never remove items from a list you are looping over — build a new list.
- Skip bad rows but collect them; silent skipping is a red flag in interviews and production.
Test yourself
1. A bad row appears at position 3 of 1000 and your loop calls break. What happens?
- That row is skipped, 999 processed
- The loop stops — 997 good rows are silently discarded
- An exception is raised
- 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?
- Inside the loop
- Before the loop
- After the loop
- 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…
- range(len(x))
- enumerate(x)
- while
- 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?
- It uses more memory
- The job hangs with no failure signal, so nothing alerts
- It corrupts data
- 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?
- [2, 5, 8]
- [2, 5, 8, 11]
- [3, 6, 9]
- [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?
- for page in range(100)
- a for loop over a list of pages
- while — continue until the cursor is empty
- 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.
Start this lesson →