Skip to content

Notes: M2: Logic & data

In M1 your program ran top to bottom, doing the same thing every time. Real software is more interesting because it reacts: it looks at data and decides, and it handles many things without you writing the same line over and over. This module gives you the two powers that turn a script into a program, making decisions and looping over data: plus the two containers that hold almost all real-world data: the list and the dictionary. The dictionary in particular is your first direct bridge to the AI half of the course: it's the exact shape data arrives in from an API.

A note on difficulty: this module has more new pieces than M1 (comparisons, if/elif/else, loops, lists, dictionaries). That's normal, and it's why the lab moves in tiny steps and splits into two parts. You do not need to memorize anything; you need to be able to read each line. Go slowly, run every cell, and lean on your partner.

Indentation: Python's most important whitespace

Before anything else, one rule that's new since M1. In Python, the spaces at the start of a line are meaningful. The lines that belong "inside" an if or a for are pushed in, indented, by 4 spaces:

for score in scores:
    print(score)        # indented → INSIDE the loop, runs each time
print("done")           # not indented → OUTSIDE the loop, runs once at the end
Most beginner errors today are indentation: a missing indent gives IndentationError. In Colab, pressing Enter after a line ending in : usually indents for you. If in doubt, line your code up with the examples.

Making decisions

Comparisons → True or False

A decision starts with a yes/no question. Comparison operators ask one and answer with a boolean (True/False):

Operator Asks 7 ? 5
== equal? False
!= not equal? True
> / < greater / less than? True / False
>= / <= at least / at most? True / False

= vs == is the classic trap. One = assigns (score = 82 puts 82 into score). Two == compares (score == 82 asks "are they equal?"). Using = where you meant == is a mistake everyone makes early.

if / elif / else

These run a block of code only when a condition is true:

if score >= 90:
    grade = "A"        # runs only if score >= 90
elif score >= 60:
    grade = "Pass"     # checked ONLY if the line above was False
else:
    grade = "Resit"    # runs if none of the above were True
Python checks top to bottom and runs the first block whose condition is True, then skips the rest. elif ("else if") lets you list several options; else is the catch-all. You can have many elifs, and elif/else are optional.

Combining questions: and, or, not

You can join conditions: and (both must be true), or (at least one), not (flips it).

if age >= 21 and money >= 5:
    print("We're getting a drink!")

Repeating with loops

The for loop: once per item

A for loop walks through a collection, handing you one item at a time:

for score in scores:    # score becomes 82, then 45, then 91, then 67
    print(score)
This is the workhorse you'll use constantly, including to loop over the results an AI model returns. for i in range(5): is a handy variant that counts 0,1,2,3,4 when you just need to do something N times.

The while loop: until a condition changes

A while loop repeats as long as a condition stays true:

count = 0
while count < 5:
    print(count)
    count += 1          # MUST move toward stopping, or the loop never ends
count += 1 is shorthand for count = count + 1. Watch out: if the condition never becomes false, you get an infinite loop (in Colab, press the ▦ stop button). Use for when you know the items; use while when you're waiting for something to change.

The two containers

Lists: many things, in order

A list holds values in order, in [ ]. You reach items by position (an index), starting at 0:

movies = ["Jaws", "Up", "Heat"]
movies[0]            # "Jaws"  (first)
movies[-1]           # "Heat"  (last)
movies[0:2]          # ["Jaws", "Up"]  (a slice: from 0 up to, but not including, 2)
len(movies)          # 3
movies.append("Alien")   # add to the end
Lists are mutable: you can change, add (append), and remove (pop) items. They're perfect for "a bunch of the same kind of thing."

Dictionaries: labelled values

A dictionary stores "key": value pairs in { }. Instead of a position, each value has a name (its key):

student = {"name": "Alice", "score": 91}
student["name"]            # "Alice", look up by key
student["grade"] = "A"     # add or change a key
del student["score"]       # remove a key
len(student)               # how many pairs
Asking for a missing key (student["age"]) raises a KeyError; student.get("age") returns None instead of erroring, which is safer when you're not sure. In modern Python, a dictionary keeps its keys in the order you added them.

flowchart TB
  subgraph List["LIST, reach by position"]
    L0["[0] Jaws"] --- L1["[1] Up"] --- L2["[2] Heat"]
  end
  subgraph Dict["DICTIONARY, reach by name"]
    K1["name → Alice"]
    K2["score → 91"]
    K3["grade → A"]
  end

Lists of dictionaries: the shape of real data

Combine them and you get the single most common shape of real-world data: a list of dictionaries: many records, each with named fields.

expenses = [
    {"item": "Coffee",    "amount": 4.50},
    {"item": "Groceries", "amount": 62.00},
]
This is exactly what an AI API hands back in M4 (and what M3's JSON is, this same shape written as text). When you can loop over a list of dictionaries and read a field by key, you can already handle an API response. That's why this module matters so much for what's coming.

Go deeper (optional, not needed for today's win) - **Truthiness:** in an `if`, Python treats `0`, `""`, `[]`, `{}`, and `None` as "falsy" (like `False`), and most other values as "truthy". So `if my_list:` means "if the list isn't empty." - **`break` and `continue`:** inside a loop, `break` exits early; `continue` skips to the next item. - **Looping a dictionary:** `for key in student:` gives you the keys; `for key, value in student.items():` gives you both at once. - **Tuples** are like lists but **immutable** (can't change), written with `( )`, e.g. a coordinate `(40.71, -74.00)`. You'll meet them occasionally; lists and dicts cover most needs.

Check yourself

Lock in today's win, answer each in your head, then reveal.

1. What's the difference between = and ==?

Show answer

= assigns: it puts a value into a variable (x = 5). == compares: it asks "are these equal?" and gives back True or False (x == 5). Using = where you meant == is a very common early mistake.

2. In if / elif / else, how many blocks run?

Show answer

Exactly one (or none, if there's no else). Python checks conditions top to bottom and runs the first block whose condition is True, then skips all the rest.

3. You have scores = [82, 45, 91]. What is scores[0], and what is len(scores)?

Show answer

scores[0] is 82: indexing starts at 0, so position 0 is the first item. len(scores) is 3: the number of items.

4. When would you use a dictionary instead of a list?

Show answer

Use a list when you have many of the same kind of thing and order/position matters. Use a dictionary when each value has a name (a label), like a record with "name", "amount", "date". Real-world data usually has names, which is why dictionaries are everywhere, and why API replies arrive as dictionaries.

5. Why does this module say a dictionary is "the shape APIs speak"?

Show answer

Because when you call an AI model (M4), its reply comes back as a dictionary of "key": value pairs, often a whole list of dictionaries. The same shape, written as text, is JSON (M3). Knowing how to read a value by its key means you can already read an API response.


New words (also in resources/glossary.md): comparison operator, boolean expression, if / elif / else, condition, and / or / not, indentation, block, for loop, while loop, iterate, range, list, index, slice, mutable, append, dictionary, key, value, KeyError, tuple.

Source: original, written for this course. Concepts and worked examples (comparisons, if/ elif/else, for/while loops, lists, dictionaries) are informed by the instructor's own Python_continuation.pdf notes in Material_AI_Engineering/; the budget-categorizer build is original. No third-party text or figures; diagrams are original. (Note: that source calls dictionaries "unordered"; modern Python (3.7+) keeps insertion order, which these notes reflect.)