← Course Home
Module 6

Loops Ramp

Loops and conditionals — the single most important thing in this whole course. Everything before this was setup; this is where scripts actually start doing real work.

Concept

What a For-Loop Does

A for-loop runs the same block of code once for every item in something — a list, a string, anything you can walk through one piece at a time (that's called an iterable). Each time through, the loop variable holds the next item.

fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)
# apple
# banana
# cherry
Lab 1

colors = ["red", "blue"]. Loop over it, printing each one.

red then blue
Lab 2

nums = [1, 2, 3]. Loop over it, printing each one.

1, 2, 3
Lab 3

Loop over a 1-item list ["only"], printing it.

only
Lab 4

Loop over an empty list [], printing each item. What happens?

Nothing prints — the loop body never runs
Lab 5

letters = ["a", "b", "c"]. Loop over it, printing each one followed by "!".

a!, b!, c!
Now go practice

Open problems/01_for_loop_basics.py and do all 5 problems locally.

Concept

Looping Over a String

Strings are iterable too — the same for walks through the characters, one at a time.

for ch in "cat":
    print(ch)
# c
# a
# t
Lab 1

Loop over "hi", printing each character.

h then i
Lab 2

Loop over "IT", printing each character.

I then T
Lab 3

Loop over the single-character string "x".

x
Lab 4

Loop over an empty string "". What happens?

Nothing prints
Lab 5

Loop over "abc", printing type() of the loop variable each time.

<class 'str'> three times — each character is still a string
Now go practice

Open problems/02_loop_string.py and do all 5 problems locally.

Concept

range() — Looping a Fixed Number of Times

range(n) generates the numbers 0 up to (not including) n — useful when you want to loop a specific number of times, not over an existing list.

for i in range(3):
    print(i)
# 0
# 1
# 2
Lab 1

Loop range(4), printing each number.

0, 1, 2, 3
Lab 2

Loop range(1), printing it.

0
Lab 3

Loop range(0). Predict, then run — what happens?

Nothing prints
Lab 4

range(2, 5) — a second number means "start here instead of 0." Loop it and print each.

2, 3, 4
Lab 5

Loop range(3), printing i + 1 each time.

1, 2, 3
Now go practice

Open problems/03_range.py and do all 5 problems locally.

Concept

Building a Result Across a Loop

Start with an empty value before the loop, then update it a little each time through. total += n is shorthand for total = total + n — same thing, shorter, and what you'll see constantly in real code.

nums = [1, 2, 3]
total = 0
for n in nums:
    total += n
print(total)   # 6
Lab 1

nums = [1, 2, 3, 4]. Sum them with a loop and total += n. Print the total.

10
Lab 2

Count how many items are in ["x", "y", "z"] by looping and incrementing a counter (count += 1) — don't use len().

3
Lab 3

words = ["a", "b", "c"]. Build one combined string by looping and result += w. Print it.

abc
Lab 4

Sum an empty list [] the same way. Print the total.

0
Lab 5

Count the characters in "hello" by looping and incrementing.

5
Lab 6

Build a new list by looping [1, 2, 3] and .append()-ing each item into an empty list. Print the result.

[1, 2, 3]
Now go practice

Open problems/04_accumulator.py and do all 6 problems locally.

Concept

Looping Over the Real USERS List

This is the payoff Module 5 was building toward — you can finally process every record, not just one at a time by index.

from fixture import USERS
for user in USERS:
    print(user["id"])
# 00u001
# 00u002
# ... all 12
Lab 1

Loop USERS, printing each id.

→ all 12 ids, 00u001 through 00u012
Lab 2

Loop USERS, printing each status.

12 lines of ACTIVE/SUSPENDED/DEPROVISIONED
Lab 3

Loop USERS, printing each profile["email"].

12 emails
Lab 4

Count how many total records there are by looping and incrementing — confirm it matches len(USERS).

12
Lab 5 · Checkpoint

Loop USERS, building a list of every id using .append() instead of printing directly. Print the final list.

A 12-item list of ids — combines sub-skills 1–4.
Now go practice

Open problems/05_real_users_loop.py — 5 problems, #5 is a checkpoint combining sub-skills 1–4.

Concept

The if Statement

if runs a block of code only when a condition is True. If it's False, the block is skipped entirely — nothing happens.

status = "ACTIVE"
if status == "ACTIVE":
    print("active user")
Lab 1

status = "ACTIVE". If it equals "ACTIVE", print "running".

running
Lab 2

status = "SUSPENDED". Same check as above. What prints?

Nothing — the condition is False
Lab 3

count = 5. If count > 0, print "has items".

has items
Lab 4

groups = []. If bool(groups), print "has groups" — reuses Module 1's truthiness.

Nothing prints — empty list is falsy
Lab 5

email = "test@example.com". If "@" in email, print "looks valid".

looks valid
Now go practice

Open problems/06_if_statement.py and do all 5 problems locally.

Concept

if / else

else runs when the if's condition was False — one of the two blocks always runs, never both, never neither.

status = "SUSPENDED"
if status == "ACTIVE":
    print("active")
else:
    print("not active")
Lab 1

status = "ACTIVE". Print "active" if so, else "not active".

active
Lab 2

status = "DEPROVISIONED". Same check.

not active
Lab 3

groups = []. Print "has groups" if truthy, else "no groups".

no groups
Lab 4

count = 0. Print "empty" if count == 0, else print the count.

empty
Lab 5

login = None. Print "never logged in" if login is None, else print login.

never logged in
Now go practice

Open problems/07_if_else.py and do all 5 problems locally.

Concept

elif Chains

elif ("else if") checks another condition only if the ones before it were False. Python checks top to bottom and stops at the first match — you can chain as many as you need, ending in an optional else for "none of the above."

status = "SUSPENDED"
if status == "ACTIVE":
    print("running")
elif status == "SUSPENDED":
    print("paused")
else:
    print("gone")
Lab 1

status = "ACTIVE". Run the three-way check above. What prints?

running
Lab 2

status = "DEPROVISIONED". Same check.

gone
Lab 3

score = 85. Print "A" if >= 90, "B" if >= 80, else "C".

B
Lab 4

score = 95. Same check.

A (stops at the first match)
Lab 5

dept = "Sales". Print "Engineering team" if Engineering, "Security team" if Security, else "Other team".

Other team
Lab 6

Loop ["ACTIVE", "SUSPENDED", "DEPROVISIONED"], printing "running"/"paused"/"gone" for each using the three-way check.

running, paused, gone
Now go practice

Open problems/08_elif.py and do all 6 problems locally.

Concept

Filtering Inside a Loop

Put an if inside a for to act on only some of the items — this combination is most of what real scripts actually do.

statuses = ["ACTIVE", "SUSPENDED", "ACTIVE"]
for s in statuses:
    if s == "ACTIVE":
        print(s)
Lab 1

nums = [1, -2, 3, -4]. Loop and print only the ones > 0.

1, 3
Lab 2

names = ["Amy", "Bo", "Charlotte"]. Print only the ones with len() > 3.

Charlotte
Lab 3

emails = ["a@x.com", "b", "c@x.com"]. Print only the ones containing "@".

a@x.com, c@x.com
Lab 4

groups = [[], ["IT"], []]. Print only the non-empty ones.

['IT']
Lab 5

Loop USERS, printing the id only for records where status == "SUSPENDED".

Bina and Rosa's ids
Lab 6

Loop USERS, printing the email only for records where status == "DEPROVISIONED".

Tri and Pat's emails
Now go practice

Open problems/09_filter_loop.py and do all 6 problems locally.

Concept

Counting With a Condition

Combine the accumulator pattern with a filter — only increment when the condition matches.

from fixture import USERS
count = 0
for user in USERS:
    if user["status"] == "ACTIVE":
        count += 1
print(count)
Lab 1

Count how many USERS records have status == "ACTIVE".

8
Lab 2

Count how many have status == "SUSPENDED".

2
Lab 3

Count how many have status == "DEPROVISIONED".

2
Lab 4

Confirm your three counts add up to len(USERS) by printing all four numbers.

8\n2\n2\n12
Lab 5 · Checkpoint

Count how many USERS records have profile["department"] == "Engineering" — combines filtering (9) and accumulation (4) on nested data.

3
Now go practice

Open problems/10_count_with_condition.py — 5 problems, #5 is a checkpoint combining sub-skills 6–9.

Concept

Looping Over a Dict's Keys

Looping a dict directly gives you its keys, one at a time — .keys() does the exact same thing, spelled out explicitly.

d = {"a": 1, "b": 2}
for k in d:
    print(k)
# a
# b
Lab 1

d = {"x": 1, "y": 2}. Loop it directly, printing each key.

x then y
Lab 2

Same dict. Loop d.keys() instead — same result.

x then y
Lab 3

scores = {"math": 90, "art": 85}. Loop it, printing each key.

math then art
Lab 4

Loop an empty dict {}. What happens?

Nothing prints
Lab 5

d = {"x": 1, "y": 2}. Loop the keys, and for each one print d[key] too — two lines per key.

x\n1\ny\n2
Now go practice

Open problems/11_dict_keys.py and do all 5 problems locally.

Concept

Looping Over a Dict's Values

.values() loops the values instead of the keys.

d = {"a": 1, "b": 2}
for v in d.values():
    print(v)
# 1
# 2
Lab 1

d = {"x": 1, "y": 2}. Loop d.values(), printing each.

1 then 2
Lab 2

scores = {"math": 90, "art": 85}. Loop the values, sum them with an accumulator.

175
Lab 3

Loop an empty dict's .values(). What happens?

Nothing prints
Lab 4

d = {"a": 5, "b": -3, "c": 2}. Loop the values, printing only the ones > 0 (filtering, from sub-skill 9).

5 then 2
Lab 5

Loop d.values() for {"active": True, "verified": False}, counting how many are True.

1
Now go practice

Open problems/12_dict_values.py and do all 5 problems locally.

Concept

Looping Over a Dict's Items

.items() gives you both the key and value together, each time through. This needs two loop variables instead of one — Python unpacks the pair automatically.

d = {"a": 1, "b": 2}
for k, v in d.items():
    print(k, v)
# a 1
# b 2
Lab 1

d = {"x": 1, "y": 2}. Loop d.items() with two variables, print both each time.

x 1 then y 2
Lab 2

scores = {"math": 90, "art": 85}. Loop items, printing an f-string like "math: 90".

math: 90 then art: 85
Lab 3

d = {"a": 5, "b": -3}. Loop items, printing only the pairs where the value > 0.

a 5
Lab 4

Loop an empty dict's .items(). What happens?

Nothing prints
Predict first

d = {"a": 1}. What happens with for k in d.items(): print(k) — only one loop variable this time?

Check
('a', 1)

With one loop variable, each item is the whole key-value pair together, shown in parentheses. Two variables is what unpacks it into separate pieces.

Now go practice

Open problems/13_dict_items.py and do all 6 problems locally.

Concept

Nested Loops

A loop inside a loop — walk every user, and for each one, walk their groups too. Remember: each group is a dict ({"id": ..., "name": ...}), so grab ["name"] from it.

for user in USERS:
    print(user["profile"]["firstName"])
    for g in user["groups"]:
        print("  " + g["name"])
Lab 1

Loop USERS, and for each one, loop their groups, printing each group's name.

Every group name across all users, grouped by user
Lab 2

Same nested loop, but print the user's firstName before each user's group names.

Lab 3

For just USERS[0] (Julio), loop his groups and print each name.

Engineering then VPN-Users
Lab 4

Count the total number of group memberships across all users (accumulator + nested loop).

15
Predict first

Dana (USERS[3]) has an empty groups list. If you print her firstName, then loop and print her group names, what shows up for the inner loop?

Check
Nothing — the inner loop body never runs for her

This is a real gotcha, not a crash: an empty list means the nested loop silently does nothing. Three users in your fixture (Dana, Tri, Pat) have this — easy to not notice if you're not looking for it.

Lab 5

Loop USERS, printing firstName for every user, then their group count (len()) right after — confirm the zero-group ones print 0, not an error.

Now go practice

Open problems/14_nested_loops.py and do all 5 problems locally.

Concept

Nested Loop + Conditional

Combine everything so far: filter which users you look at, then loop into their nested data.

for user in USERS:
    if user["status"] == "ACTIVE":
        for g in user["groups"]:
            print(g["name"])
Lab 1

Print every group name, but only for ACTIVE users.

13 group names total
Lab 2

Print every group name, but only for SUSPENDED users.

Bina's and Rosa's groups only
Lab 3

Count total group memberships across only ACTIVE users (accumulator + filter + nested loop).

13
Lab 4

Print the firstName of every ACTIVE user who has at least one group (skip the ones with zero, using an if on the group list's truthiness).

Lab 5 · Checkpoint

Loop USERS; for each ACTIVE user, print their firstName, then loop their groups printing each name indented — a real filtered nested report. Combines sub-skills 9–14.

Now go practice

Open problems/15_nested_plus_conditional.py — 5 problems, #5 is a checkpoint combining sub-skills 9–14.

Concept

The Missing-Key Crash in a Loop

You've seen a single missing key crash before. Now watch what it looks like across a full loop — this is the single most realistic bug shape in IT scripting.

Predict first

Loop USERS, printing user["profile"]["department"] for every record. Will it finish all 12? If not, how far does it get?

for user in USERS:
    print(user["profile"]["department"])
Check
Crashes after printing 7 departments — KeyError: 'department'

Records 1–7 work fine, then record 8 (Layla, USERS[7]) has no department key and the whole script dies. This is exactly why "it worked when I tested it" isn't good enough — you tested on the records that happened to be complete.

Lab 1

Confirm it yourself: run the loop above, count how many lines printed before the crash.

7
Lab 2

Print USERS[7]["profile"] directly — see for yourself that department is missing.

No department key in the dict
Lab 3

Loop just USERS[0:3] (a slice) the same way — no crash, since none of the first 3 are missing the key.

3 departments print fine
Lab 4

Loop USERS printing lastLogin for every record — this one won't crash. Why not, even though Dana's is None?

Printing None is fine — it only crashes when you try to use it, like gluing text onto it
Now go practice

Open problems/16_missing_key_crash.py and do all 4 problems locally.

Concept

Guarding Loop Bodies With if

Fix the crash from last section: check whether the key exists before using it, so the loop can keep going instead of dying.

for user in USERS:
    profile = user["profile"]
    if "department" in profile:
        print(profile["department"])
    else:
        print("Unknown")
Lab 1

Run the guarded loop above. Confirm it finishes all 12 records without crashing.

12 lines, one says Unknown
Lab 2

Same idea, but use .get("department", "Unknown") instead of the if/in check — shorter, same result.

Same 12 lines
Lab 3

Loop USERS, printing lastLogin using .get("lastLogin", "Never") — Dana's None stays None though, since the key IS present, just empty. Notice the difference from missing entirely.

Dana's line still shows None, not Never
Lab 4

Count how many users are missing a department key, using the in check inside a loop with an accumulator.

1
Lab 5

Loop USERS, printing f"{firstName}: {department}" using the guard pattern, for every record, no crash.

12 lines, Layla's says Unknown
Now go practice

Open problems/17_guard_pattern.py and do all 5 problems locally.

Concept

Joining Two Data Sources in a Loop

Loop one dataset, and for each record, look something up in a completely different one — this is how you'd combine two separate API responses in real life.

for user in USERS:
    email = user["profile"]["email"]
    count = LOGIN_COUNTS.get(email, 0)
    print(f"{email}: {count}")
Lab 1

Run the join loop above for all 12 users.

12 lines, most with real numbers, some with 0
Predict first

Kelly O'Connor's real email is kokonnor@example.com. What will her line in the loop above show?

Check
kokonnor@example.com: 0 — wrong, not crashed

This is the real typo bug from your fixture: LOGIN_COUNTS has "koonnor@example.com" misspelled, so the lookup silently misses and falls back to the default. No error, no warning — just quietly wrong data. This is worse than a crash, because nothing tells you to go look.

Lab 2

Count how many users have a login count of exactly 0 from the join (genuinely missing, typo'd, or actually recorded as 0).

5
Lab 3

Loop USERS, printing only the ones where the join found a count > 0.

7 lines
Lab 4

Print the total of all login counts found across every user, using an accumulator.

589
Now go practice

Open problems/18_join_in_loop.py and do all 4 problems locally.

Concept

List Comprehensions

A one-line loop that builds a new list — the same "filter inside a loop" pattern from sub-skill 9, just compressed onto one line.

# The long way:
active_emails = []
for u in USERS:
    if u["status"] == "ACTIVE":
        active_emails.append(u["profile"]["email"])

# The comprehension way -- same result:
active_emails = [u["profile"]["email"] for u in USERS if u["status"] == "ACTIVE"]
Lab 1

nums = [1, 2, 3, 4]. Build a list comprehension that keeps only the ones > 2.

[3, 4]
Lab 2

Build a comprehension of every user's id from USERS (no filter this time).

All 12 ids
Lab 3

Build a comprehension of firstName for every SUSPENDED user.

['Bina', 'Rosa']
Lab 4

Build the active-emails comprehension from the example, then print its len().

8
Lab 5

Build a comprehension of every group name a user has, for just USERS[9] (Marcus) — comprehension over a nested list.

['Engineering', 'Admins', 'VPN-Users']
Now go practice

Open problems/19_list_comprehension.py and do all 5 problems locally.

Concept

Full-Fixture Report

Everything in this module, combined into one real script over all 12 records.

Lab 1

Loop all USERS, and using the guard pattern, print f"{firstName} ({dept})" for each — no crash on Layla.

12 lines
Lab 2

For each user, nested-loop their groups and count the total, printing f"{firstName}: {group_count} groups".

12 lines, three showing 0 groups
Lab 3

Using a list comprehension, build the list of every ACTIVE user's email, print it and its length.

8 emails
Lab 4

Loop and join with LOGIN_COUNTS, counting how many users have 0 logins found (missing, typo'd, or actually recorded as 0).

5
Lab 5

Using .items(), loop LOGIN_COUNTS directly and print every email/count pair as f"{email}: {count}".

9 lines
Lab 6 · Final checkpoint

One script, using every sub-skill 1–19 at least once: loop all USERS (filter to ACTIVE only), guard the department lookup, nested-loop groups and count them, join with LOGIN_COUNTS, and finish with a comprehension summarizing all active emails. Print a report line per active user, then the final email list.

This is the big one — take your time.
Now go practice

Open problems/20_full_fixture_report.py — 6 problems, #6 is the final checkpoint for all of Module 6.

Complete

Module 6 done

for-loop → range() → accumulator → if/else/elif → filtering → dict keys/values/items → nested loops → missing-key crash → guarding → joining → comprehensions.

Run python check.py in problems/ to grade everything.