Chapter 3 — Programming I
Lesson map
Lesson 03 published. Map, example, EX007.
flowchart TD
N0["Learning outcomes"]
N1["3.1 Counting records"]
N2["3.2 Lists and dictionaries"]
N3["Lab — Counting reports by branch"]
N4["3.3 Testing with known inputs"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Worked example"]
EX --> Q["Exercise EX007"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["3.1 Counting records"]
N2["3.2 Lists and dictionaries"]
N3["Lab — Counting reports by branch"]
N4["3.3 Testing with known inputs"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX007"]
[Learning outcomes]
|
v
[3.1 Counting records]
|
v
[3.2 Lists and dictionaries]
|
v
[Lab — Counting reports by branch]
|
v
[3.3 Testing with known inputs]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX007]
Learning outcomes
You will (1) write simple Python to count and summarise records; (2) use lists and dictionaries for behaviour data; (3) test a script with known inputs.
3.1 Counting records
Nadia writes her first Python script to count suspicious email reports by branch. Each record is a line with a date, branch and verdict. The script reads the lines, splits each into fields and adds one to a counter for the branch. Python's dictionary is ideal for this, because it maps each branch name to its count. She prints the totals in order. Even a simple count is useful: it shows that two branches with public computers report far more emails than the others, which raises a question worth exploring.
3.2 Lists and dictionaries
A list holds items in order, such as all report dates, while a dictionary holds pairs, such as branch and count. Nadia uses a list of dictionaries, one per report, so each report keeps its fields together. She then filters the list to find malicious reports and groups them by branch. She learns to keep data synthetic and free of personal names, since even practice code should respect privacy. Good habits learned on small scripts carry into larger projects later in the course.
Lab — Counting reports by branch
# Count synthetic suspicious-email reports by branch.
rows = ["2026-01-03,Central,malicious", "2026-01-04,Riverside,harmless"] + \
[f"2026-{2 + d // 28:02d}-{1 + d % 28:02d},{b},{v}" for d, (b, v) in enumerate(
[("Central", "harmless")] * 13 + [("Riverside", "malicious")] * 9 + [("Hill", "harmless")] * 6 +
[("Market", "harmless")] * 5 + [("Oakfield", "malicious")] * 4 + [("Mill", "harmless")] * 3 +
[("Quay", "harmless")] * 3 + [("Elm", "harmless")] * 2 + [("Abbey", "malicious")] * 1, start=1) if True]
counts = {}
for r in rows:
parts = r.split(",")
if len(parts) != 3: print("skip", r); continue
counts[parts[1]] = counts.get(parts[1], 0) + 1
for b, c in sorted(counts.items(), key=lambda x: -x[1]): print(b, c)
print("total", sum(counts.values()))
Run with python3 lab_count.py. Verified output:
Central 14
Riverside 10
Hill 6
Market 5
Oakfield 4
Mill 3
Quay 3
Elm 2
Abbey 1
total 48
3.3 Testing with known inputs
Nadia tests her script by creating a tiny file with five reports whose totals she knows. If the script's output matches her hand count, she gains confidence. She also tests an empty file and a line with a missing field, and adds a check that skips broken lines with a warning. Testing with known inputs is a basic discipline in programming, and it matters in security work because wrong counts can lead to wrong decisions about where to invest effort or training.
Worked example
Nadia counts synthetic reports by branch with a dictionary, groups malicious reports and tests her script with known inputs.
Synthetic case. The data are synthetic.
Errors and limits
Broken lines may hide real problems. Small tests do not prove correctness.
Exercises
- EX007 — Dictionary use. Why is a dictionary suited to counting by branch? Rubric: 3 = it maps each branch to its count;; 2 = mapping;; 1 = list order;; 0 = none.
- EX008 — Top branch. Which branch reported most in the lab? Rubric: 3 = Central with 14;; 2 = Central;; 1 = vague;; 0 = none.
- EX009 — Broken lines. How does the script handle a line with a missing field? Rubric: 3 = skips it with a warning;; 2 = skip;; 1 = crash;; 0 = none.
Synthesis
Simple, tested scripts turn records into counts that raise useful questions.
Continue studying — chapter 03 of 40
← Chapter 02 (draft) · Course chapter index · Chapter 04 (draft) →