Skip to main content
PROGRAMMING / PYTHON / LESSON 03

Python Control Flow.

Go beyond individual statements. Learn to make decisions, repeat work with loops, and debug exactly why a script stops—or keeps running.

Foundations → Intermediate60–80 minutesCode execution in browserNo install or account
00

What you'll learn

A useful script rarely evaluates a single variable once. It makes decisions, processes multiple records, and knows when to stop. This lesson builds those skills with small, readable examples before introducing a real coding exercise.

  • Explain how Python evaluates if / elif / else in order and selects one branch.
  • Predict how for loops iterate over ranges and small collections, including exclusive stop values.
  • Use counters and accumulators to summarize repeated checks.
  • Write bounded while loops with clear exit conditions.
  • Distinguish break from continue and trace their effect on execution.
  • Debug indentation, off-by-one errors, and loops that fail to update state.
  • Predict nested-loop iteration counts and safely filter site/service combinations using two loops.
Our approach: Predict which branch or iteration should run, trace the state, then write the correction yourself. Keep the original business requirement in view.
BRANCHES SELECT THE NEXT ACTION
01

From one if to several decisions

Sometimes a device is neither simply healthy nor unhealthy. Python's if, elif and else chain examines conditions from top to bottom. It executes the first matching branch and skips the rest, even when a later comparison could also be true. Order the most specific conditions intentionally.

One branch wins

An elif is tested only when earlier if/elif conditions were false. else runs only if none of the previous conditions matched; it has no condition of its own.

Threshold order matters

For a priority scale, test latency >= 200 before latency >= 100. If the broad check comes first, a value of 240 may be incorrectly labeled 'warning' instead of 'critical'.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
latency = 240
if latency >= 200:
    print("Critical")
elif latency >= 100:
    print("Warning")
else:
    print("Normal")
What would print if latency were 140? What if it were exactly 200? Reveal explanation after you predict.

140 prints Warning. 200 prints Critical because the first comparison includes the boundary.

Remember: Python selects one branch in an if/elif/else chain. Arrange thresholds in the order your rules require.
REPEAT WITHOUT DUPLICATION
02

A for loop visits each item

When a technician needs to inspect several records, writing the same test five times is error-prone. A for loop binds a variable to each item in an iterable and executes its indented block once for each item. For now, a short list represents an inventory; we'll explore data structures deeply in a later lesson.

Loop variable

In for name in devices:, name takes the next item from devices. The original collection isn't automatically modified by visiting it.

Indentation defines repetition

print(name) inside the loop runs for every item. Put print('Done') outside the loop to run once after the entire iteration finishes.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
devices = ["SW-01", "FW-01", "AP-02"]
for name in devices:
    print(name)
print("Inventory reviewed")
How many times does the final line print? Why? Reveal explanation after you predict.

Inventory reviewed prints once because its statement is outside the indented loop body.

Remember: The loop variable changes to the next item each iteration. Everything indented inside the loop repeats.
STOP VALUES ARE EXCLUSIVE
03

Understand range before writing counters

range(start, stop, step) produces a sequence of integer values. Its stop value is not included, so range(1, 4) visits 1, 2 and 3. If you forget the exclusive boundary, your final port or retry count may silently be missed.

One argument

range(4) visits 0, 1, 2, 3. Zero-based counting is common, but make sure it matches the task's requirements.

Three arguments

range(2, 9, 3) visits 2, 5, 8. A positive step must move toward the upper bound, while a negative step can count downward.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
for attempt in range(1, 4):
    print(f"Attempt {attempt}")
How many attempts are printed, and what would range(1, 5) do? Reveal explanation after you predict.

Three attempts are printed: 1, 2 and 3. range(1, 5) adds a fourth attempt.

NORTHSTAR / CONTROL FLOW EXPLORER

See every iteration.

Predict what the loop will do, change the conditions, then step through its decisions. The editable workbench later in this lesson runs actual Python.

SOURCE CODE
for attempt in range(1, 4):
    print(f"Attempt {attempt}")
EXECUTION1 / 5
Setup—

Predict the result before executing the first iteration.

OUTPUT SO FAR
(nothing yet)

Educational trace of three fixed examples; Python execution and variable tracing are available in the full workbench.

Remember: Use a half-open interval: start is included, stop is excluded. Predict exact values before executing.
SUMMARIZE REPEATED OBSERVATIONS
04

Count a result without losing state

Sometimes you want a single report from many records. An accumulator is a variable initialized before the loop and updated inside it. Resetting a counter inside the loop discards previous results, and printing inside the loop may produce intermediate values rather than the requested final summary.

Initialize before the loop

Start offline_count = 0 before visiting devices. Each offline record increases it by one. This counts matches rather than the total inventory size.

Separate process from report

A final print statement is often outside the loop. If it's accidentally indented, a report prints repeatedly before the scan finishes.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
statuses = ["online", "offline", "offline", "online"]
offline_count = 0
for state in statuses:
    if state == "offline":
        offline_count += 1
print(f"{offline_count} offline devices")
What would go wrong if offline_count = 0 were placed immediately under for? Reveal explanation after you predict.

It would reset the count every iteration, so the final result would reflect only the most recent item instead of all offline records.

Remember: Initialize once, update conditionally for each item, then print the completed summary after the loop.
REPEAT WHILE A CONDITION IS TRUE
05

A while loop needs a way out

A for loop is ideal for a known sequence. A while loop repeats for as long as a condition remains true, which can model retries or waiting for a result. Unlike a for range, your code usually must update the condition's state. Missing that update causes an endless loop.

Check before every iteration

while attempt <= 3: evaluates its Boolean condition before the body. Once attempt becomes 4, the loop stops normally.

Avoid unbounded behavior

while True: requires a deliberate break or other exit. In the beginner workbench, use explicit counters and avoid real network retries.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
attempt = 1
while attempt <= 3:
    print(f"Checking attempt {attempt}")
    attempt += 1
print("Finished")
What does attempt contain when the loop finishes? Reveal explanation after you predict.

4. The last completed body increment moves attempt from 3 to 4, so the next condition fails.

Remember: For bounded retries, define a maximum, change the counter every iteration and test the exact boundary.
SKIP A STEP OR STOP THE LOOP
06

continue is not break

When scanning event codes, some entries may be irrelevant while others require stopping the investigation. continue skips the rest of the current iteration and moves to the next item; break exits the nearest enclosing loop. Confusing them can skip an important record or stop a report too early.

Skip a harmless record

An HTTP 200 can be skipped if you're building a report of unusual responses. continue returns to the next loop iteration, not the line after the entire loop.

Stop on a critical response

If the workflow needs the first server error (HTTP 500+), break prevents examining later entries. Whether stopping early is appropriate depends on the task.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
responses = [200, 429, 503, 200]
for code in responses:
    if code == 200:
        continue
    if code >= 500:
        print(f"Critical: {code}")
        break
    print(f"Review: {code}")
Which responses are printed before the loop stops? Reveal explanation after you predict.

Review: 429 and then Critical: 503. The 200 is skipped; break prevents examining the last item.

Remember: continue means 'next item'; break means 'stop this loop.' Both only affect the innermost enclosing loop.
COMBINE REPETITION WITH DECISIONS
07

Read nested logic one level at a time

A nested loop means a complete inner loop runs once for every outer-loop item. For two sites and three services, Python visits six site–service combinations in a predictable order. Trace the outer item, then walk the full inner sequence before the outer loop advances. An if statement inside a loop is different: it makes a decision but does not create additional iterations.

Outer and inner responsibilities

for site in sites: chooses a site. The indented for service in services: checks each service at that one site. When services are exhausted, the outer loop selects the next site.

Count the iterations

If sites contains 2 items and services contains 3, the inner body executes 2 × 3 = 6 times. An empty inner list yields zero visits regardless of how many outer items exist.

Indentation reveals structure

A report printed inside the inner loop runs for every pair. A report after the inner loop, but still inside the outer loop, runs once per site. The variable names and indentation tell you which is intended.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
sites = ['HQ', 'BR1']
services = ['dns', 'dhcp', 'vpn']
checks = 0
for site in sites:
    for service in services:
        checks += 1
        print(f'{site}: {service}')
print(f'{checks} total checks')
List the first three lines. Which site appears when the fourth service check starts, and how many checks print at the end? Reveal explanation after you predict.

The first lines are HQ: dns, HQ: dhcp, and HQ: vpn. The fourth visit starts BR1: dns because the inner loop finishes for HQ before the outer site advances. The last line is 6 total checks.

Remember: In nested loops, the inner loop restarts for every item in the outer loop. Count pairs and trace indentation.
A COMPLETE PASS FOR EACH OUTER ITEM
08

Trace a grid and filter combinations

For a two-dimensional grid, a schedule, or a small site-by-service checklist, two loops describe two coordinates. Each outer item is paired with each inner item in order. To filter the combinations, put an if statement inside the inner loop. A useful debugging habit is to record the pair before deciding whether it matches: this shows whether a bug comes from the loop boundary, the condition, or the output. Avoid accidentally resetting the result list inside the outer loop.

Pairwise traversal

The row/column combinations in a 2 × 3 grid are (0,0), (0,1), (0,2), (1,0), (1,1), (1,2). range(2) yields only 0 and 1; range(3) yields 0, 1 and 2.

Filter the pairs

When a particular site and service are in a fictional failures set, report the matching pair; otherwise continue. A set is convenient for membership, but simple lists work too.

Empty collections and loop placement

An empty rows or columns sequence means no combinations. Initialize the count or result once before both loops, then produce the final report only after both loops finish.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
sites = ['HQ', 'BR1']
services = ['dns', 'vpn']
failed = {'HQ:vpn', 'BR1:dns'}
matches = []
for site in sites:
    for service in services:
        pair = f'{site}:{service}'
        if pair in failed:
            matches.append(pair)
print(sorted(matches))
What list prints? Why doesn't the algorithm report HQ:dns or BR1:vpn, and what if services is empty? Reveal explanation after you predict.

It prints ['BR1:dns', 'HQ:vpn'] after sorting. The other two pairs are not in the failures set, so they are skipped. If services is empty, the inner loop never runs and matches stays empty.

INTERACTIVE / NESTED LOOP STEPPER

One outer item. Every inner item.

Step through a fictional site-by-service grid. The inner loop visits every service at the selected site before the outer loop advances.

1HQdns
2HQvpn
3HQweb
4BR1dns
5BR1vpn
6BR1web

Visit 1 of 6: outer site = HQ; inner service = dns

for site in sites:
    for service in services:
        print(site, service)
Remember: Place an if inside two loops to test pairs, while keeping the result container outside both loops.
TRACE → CORRECT → VERIFY
09

Debug the loop, not just the output

A loop can be valid Python and still be wrong. Typical problems include an off-by-one range, a misplaced counter initialization, a print statement at the wrong indentation, a condition that never changes, or using break where continue was intended. Start from the observed behavior and compare each iteration to the requirement.

Follow variable snapshots

The Python workbench displays state before each executed line and the final state. Use it to see whether a counter changes after an if, and whether a while condition eventually becomes false.

Test more than one sample

After the initial exercise succeeds, edit the data and check boundaries. Does your script still work for zero matches, one match and several matches? Real automation must survive unexpected inputs.

PYTHON / REASON THROUGH THE OUTPUTRead before you run
ports = [22, 80, 443, 3389]
review_count = 0
for port in ports:
    if port == 22 or port == 443:
        continue
    review_count += 1
print(f"{review_count} ports need review")
Which values contribute to review_count? Reveal explanation after you predict.

80 and 3389. The 22 and 443 entries trigger continue and are not counted.

Remember: Correctness means the intended records were processed, the loop terminates and the final output matches the requirement.
10 / APPLY IT YOURSELF
10

Turn control flow into working code

The first challenge asks you to fix overlapping latency thresholds using if/elif/else. Run real Python, predict the output, inspect the trace, then continue into loops, bounds, nested-loop grids and a simulated port audit in Practice.

JOELEARNS / PYTHON WORKBENCH

Write it. Run it. Understand it.

Write decisions and loops, inspect each iteration, and use feedback to verify the exact result.

Python 3.14 · in-browser
CHALLENGE 01 / 8 · BEGINNER

Classify latency without overlapping rules

Northstar classifies latency at 200 ms or higher as Critical, at 100–199 as Warning, and below 100 as Normal. The current test is 240 ms. Fix the decision order so the exact output is 'Critical'; keep the result in the variable severity.

EXPECTED OUTPUTCritical
script.py editableCtrl / Cmd + Enter to run
Your code is stored only in session storage when enabled. Never paste secrets. Clearing this option clears saved drafts, not the editor.
Code executes only when you choose Run or Check. No account needed.
HINTS · OPTIONAL

Try solving it before asking for help. Hints never show a completed program.

PYTHON OUTPUTReady

Your printed output and errors will appear here.

VARIABLE TRACER

Run the code, then step through the executed lines to watch variable values change.

About this environment: The Python runtime is loaded on demand from a version-pinned CDN and runs inside a sandboxed, opaque-origin browser frame. Runs have a time limit. OS/network automation is outside this introductory workbench. If your code calls input(), a response panel appears to supply text to those calls. Don't paste secrets or untrusted scripts.

Next required step: complete the 8-challenge Practice milestone →
TAKE THE NEXT STEP

Practice is where you become independent.

Seven further challenges build from for/range and bounded while loops to nested-grid traversal, pair matching and an IT-flavored inventory audit. Each asks you to write or correct the logic, rather than only identify the right answer.

Continue to all Control Flow challenges →
11

Reference material

You don't need to memorize everything. Learn how to read the Python documentation and use it when a behavior is unfamiliar.

NEXT REQUIRED STEP · PYTHON FUNDAMENTALS

Complete the Practice milestone

You've reached the end of this written lesson. Your next step is practice—complete Python Control Flow Coding Challenges before proceeding to a new lesson. This is milestone 6 of 18. You can revisit the explanation whenever you need it.