Course / 04 Code / Lesson 06 of 11

Variables, strings, lists, dicts, conditions, loops

Estimated time: 25 min reading · 25 min activity

A short script can decide which records to count. To predict its result, follow the values stored under each name and check the condition for each record. Work in two sittings if useful: first the small Python forms, then the JSON counting activity.

A variable is a name referring to a value. In Python, str means text, or a string; int means an integer, a whole number. Quotes make "1" text, while 1 without quotes is a number. The assignment sign = gives a name its value. A list holds an ordered sequence, written inside square brackets. Its first item has index 0, meaning position zero.

A dictionary, or dict, stores key–value pairs inside braces. The key is the name used to retrieve its paired value. In {"lab": 1}, the text key lab is paired with the number 1. A colon separates key from value. This lets a record name facts such as status rather than requiring you to remember a numeric position.

Before you begin

Estimated time
25 min reading, 25 min activity. Setup and optional practice may take longer.
Where you work
Read and trace the supplied source and input in your browser. A later optional run uses Python 3.12 and its standard library in a fresh directory under your own ~/yanosec-lab. The ~ means your home directory. Keep paired files together and avoid overwriting existing work. No extra packages or network calls are required.
Without a lab
Follow each source line against the supplied input and predicted trace. You can complete the same reasoning without running Python; the practical run can wait. Earlier recorded Python results are labeled separately from predictions. Reading works without JavaScript. Answer checking needs JavaScript and a secure context; saving additionally needs usable browser storage.

After this lesson you can:

  • Trace a condition inside a loop over a list of records.
  • Look up one value by a dict key rather than by position.
  • Read this lesson's JSON object as text that json.load would turn into dicts and lists.

01Example

Read the worked lookup and loop separately. scores["lab"] retrieves the value paired with lab. The for statement takes each item from labels in turn. The indented print belongs to that loop and therefore runs once for each item. These are predictions from the source.

scores = {"lab": 1}
print(scores["lab"])
Predicted print: 1

labels = ["red", "blue"]
for label in labels:
    print(label)
Predicted lines: red, then blue

The quotes around lab make a string key. The value 1 has no quotes, so it is a number.
"1" would be text and would not be the same value.

02A list position is not a dict key

Use square brackets to look up an item, but inspect what is inside them. labels[0] uses a list position; scores["lab"] uses a dictionary key. Python dictionaries preserve insertion order, but their lookup is still by key, not by numeric position. A missing key causes an error rather than supplying an automatic zero.

A condition is a test that chooses whether an action happens. The operator == compares values; it differs from =, which assigns a value. An if line ends in a colon, and the indented statements beneath it run only when its condition is true. A for line also ends in a colon and repeats its indented body for each item. The extra indentation in the activity puts the addition inside both the loop and the condition.

JSON, short for JavaScript Object Notation, is a text format for data. A JSON object contains named pairs; an array contains an ordered list. Python’s json module is part of its standard library, the tools supplied with Python. import json makes that module available, and json.load reads JSON from a file. The activity’s object becomes a dict and its array becomes a list. The file contains data, not Python instructions.

A string dict key selects numeric 1; a separate list loop visits red and blue and prints each value in order.Model. A teaching model drawn by hand. It shows the idea, not real tool output.

Read the full explanation below.

Playback is optional. Step through at your own pace.

Instruction being read

print(scores["lab"])

Two separate worked examples

scores = {"lab": 1}
print(scores["lab"])

labels = ["red", "blue"]
for label in labels:
    print(label)

source

Current key/loop value

scores["lab"] = 1 (number)

predicted

Predicted stdout

1

predicted

The string key lab selects numeric value 1 and predicts printing 1.

Follow the explanation

  1. The string key lab selects numeric value 1 and predicts printing 1.
  2. In the separate loop, label first becomes red and prints red.
  3. The next loop value is blue; the loop has printed red then blue.
Read every state and value

1. The string key lab selects numeric value 1 and predicts printing 1.

Current command
lookup
Data in each location
Pane: Two separate worked examples; Text: scores = {"lab": 1} print(scores["lab"]) labels = ["red", "blue"] for label in labels: print(label); Status: Two separate worked examples · Pane: Current key/loop value; Text: scores["lab"] = 1 (number); Status: predicted · Pane: Predicted stdout; Text: 1 ; Status: predicted
Links
From: Two separate worked examples; To: Current key/loop value; Label: dict-key lookup · From: Current key/loop value; To: Predicted stdout; Label: print numeric value

2. In the separate loop, label first becomes red and prints red.

Current command
for label in labels: print(label)
Data in each location
Pane: Two separate worked examples; Text: scores = {"lab": 1} print(scores["lab"]) labels = ["red", "blue"] for label in labels: print(label); Status: Two separate worked examples · Pane: Current key/loop value; Text: label = red (string); Status: predicted · Pane: Predicted stdout; Text: red ; Status: predicted
Links
From: Two separate worked examples; To: Current key/loop value; Label: first list value · From: Current key/loop value; To: Predicted stdout; Label: first loop print

3. The next loop value is blue; the loop has printed red then blue.

Current command
for label in labels: print(label)
Data in each location
Pane: Two separate worked examples; Text: scores = {"lab": 1} print(scores["lab"]) labels = ["red", "blue"] for label in labels: print(label); Status: Two separate worked examples · Pane: Current key/loop value; Text: label = blue (string); Status: predicted · Pane: Predicted stdout; Text: red blue ; Status: predicted
Links
From: Two separate worked examples; To: Current key/loop value; Label: second list value · From: Current key/loop value; To: Predicted stdout; Label: next loop print
A string dict key selects numeric 1; a separate list loop visits red and blue and prints each value in order.

03Count the ready records

The activity files contain three records and a script that counts records whose status is ready. A record here is a small dictionary describing one item. Follow the source against all three records before reading the predicted trace.

{
  "records": [
    {"id": "n1", "status": "ready"},
    {"id": "n2", "status": "hold"},
    {"id": "n3", "status": "ready"}
  ]
}

Download the JSON records

import json

with open("records.json", encoding="utf-8") as handle:
    payload = json.load(handle)

chosen = 0
for record in payload["records"]:
    if record["status"] == "ready":
        chosen = chosen + 1

print(chosen)

Download the counting script

Predicted intermediate trace. The script prints only the final count:
n1 status ready -> chosen becomes 1
n2 status hold  -> chosen stays 1
n3 status ready -> chosen becomes 2
print(chosen) -> 2
  1. In records.json, find the outer object, its records key, and the array inside square brackets. Read the three status values: ready, hold, ready.
  2. Read python-basics.py. The with block opens records.json as UTF-8 text, names the open file handle, and lets json.load read it. Leaving with closes the file. payload is the resulting outer dictionary.
  3. Start chosen at 0. For each record in payload["records"], compare record["status"] with ready. Add one only when they match. Your running counts should be 1, 1, and 2. The addition reads the old chosen value before assigning the new one.
  4. Compare with the predicted trace: the script prints only the final 2. A prior Python 3.12.3 run recorded that final line. Stop after tracing, or later place both unchanged files in a fresh lab directory and enter python3 python-basics.py there. No extra JSON package is needed.

04Optional challenge

Spend about ten extra minutes imagining one added record with id n9 and status ready. Trace all four records without editing the download. The predicted total becomes 3 because three statuses match. Explain which condition caused each addition.

05Fresh cases for the checks

Use these fictional cases for the checks below. They have different inputs from the worked examples. Read them here or make notes; no installation or external service is needed.

Python card A: predict a complete source caseOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

records = [
    {"id": "a7", "status": "wait"},
    {"id": "b4", "status": "send"},
    {"id": "c8", "status": "wait"},
]
chosen = 0
for record in records:
    if record["status"] == "send":
        chosen = chosen + 1
print(chosen)
 
Source-reading case only; this code was not run.

Python card B: an independent condition diagnosisOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

The loop visits these four dictionaries in the printed order:
{"id": "k2", "status": "ready"}
{"id": "m9", "status": "ready"}
{"id": "p5", "status": "paused"}
{"id": "v3", "status": "ready"}
 
The addition is inside this condition:
if record["status"] == "ready":
    chosen = chosen + 1
Assume chosen starts at 0. No other statement changes it.

Python card C: JSON text for interpretationOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

{
  "records": [
    {"id": "r6", "status": "held"}
  ],
  "limit": 8
}
 
Assume json.load reads this valid JSON into a name called payload.

Python card D: change one comparisonOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

records = [
    {"id": "t8", "status": "open"},
    {"id": "u2", "status": "wait"},
    {"id": "w6", "status": "open"},
]
chosen = 0
for record in records:
    if record["status"] == "open":
        chosen = chosen + 1
print(chosen)
 
For the changed case, replace only the comparison string "open" with "closed".
Leave every dictionary, the starting count, and the indentation unchanged.
Predict from the source; no run is recorded.

Python card E: optional key repairOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

records = [
    {"id": "q4", "name": "memo", "stage": "send"},
    {"id": "q9", "name": "list", "stage": "wait"},
]
 
Intended rule: count a record when its processing state is send.
Current condition: if record["name"] == "send":
Change only the dictionary key inside the square brackets.

06Explain a conditional count

Optional self-check: choose one card and explain why a loop can visit a record without increasing the count. Explain how a dictionary key differs from a list position.

Check your explanation: name the value retrieved by the key, compare it with the condition's string, connect the result to the indented addition, and distinguish the final print from intermediate counts. A JSON array becomes a list; a JSON object becomes a dict. These are predictions from supplied source, not observations of an execution.

07Common mistakes

If hold is counted, check the condition and indentation. Only the indented addition under a true ready comparison should change chosen.

If a quoted digit is treated as a number, inspect the quotes before doing arithmetic. The text "2" and integer 2 are different values.

If a JSON record is treated as Python code, return it to the data file. Let the JSON reader interpret its format; do not paste an entire data file into an interactive prompt.

References