Every Python construct used in this book — checked against every snippet in all 19 lessons — explained through the Swift you already speak. Read it once now, keep it open beside any lesson. All outputs shown were produced by actually running the code.
1. Indentation IS the syntax. No braces. A colon opens a block; the indented lines below belong to it; un-indenting closes it. Mis-indent and you change the program.
2. No declarations. No let/var: x = 0.5 both creates and assigns. Nothing is immutable by default.
3. No declared types. x can hold a number now and a list later (don't, but it can). Types exist — they're just not written.
4. Spelling: True, False, None (capitalized; None ≈ nil); and, or, not instead of &&, ||, !; snake_case instead of camelCase; # for comments.
5. No semicolons, no parentheses around conditions: if z > 0: not if (z > 0) {.
| Swift | Python | notes |
|---|---|---|
| var w = 0.0 let lr = 5.0 | w = 0.0 lr = 5.0 | same thing; no var/let distinction |
| var a = 0.0, b = 1.0 | a, b = 0.0, 1.0 w1, w2, b = 0.5, -0.4, 0.1 | multiple assignment, used all over lessons 9–10 |
| pow(2.0, 10.0) | 2 ** 10 # 1024 | ** is power; (w - 3) ** 2 in lesson 7 |
| z += w * x | z += w * x | identical |
An f-string is Python's string interpolation: prefix f, then {expression} inside — Swift's \(expression) with curly braces. After a colon comes a format spec, replacing Swift's String(format:):
| Swift | Python | actual output |
|---|---|---|
| print("a = \(a)") | print(f"a = {a}") | — |
| String(format: "%.2f", 3.14159) | f"{3.14159:.2f}" | 3.14 |
| String(format: "%3d", 7) | f"{7:3d}" | 7 |
| String(format: "%+5.1f", 0.5) | f"{0.5:+5.1f}" | +0.5 |
| // pad to width 5 | f"{'cat':5s}" | cat |
Decode {loss:.4f}: print loss as a float with 4 digits after the point. {epoch:4d}: integer, right-aligned to width 4. That's 90% of the book's printing.
| Swift | Python | notes / output |
|---|---|---|
| var xs = [10, 20, 30] xs[0] xs.count xs.append(7) | xs = [10, 20, 30] xs[0] len(xs) xs.append(7) | len() is a function, not a property |
| Array(xs[1...]) Array(xs[..<2]) | xs[1:] # [20, 30] xs[:2] # [10, 20] | slicing; works on strings too: "to be"[1:] → 'o be'. s[1:] in lesson 14 means "the string without its first character" |
| [[1.0, 2.0], [3.0, 4.0]] W[n][i] | [[1.0, 2.0], [3.0, 4.0]] W[n][i] | list of lists = our weight matrices, identical syntax |
| parts.joined(separator: "-") | "-".join(parts) | 'a-b-c' # separator first! |
| Swift | Python | notes |
|---|---|---|
| var emb = ["king": [1.0, 2.0]] emb["king"]! // crash if absent emb["x"] != nil | emb = {"king": [1.0, 2.0]} emb["king"] # crash if absent "x" in emb | Python's d[k] behaves like Swift's force-unwrap — it throws if the key is missing. in tests membership (also works on lists and strings) |
| for (k, v) in emb { } | for k, v in emb.items(): | .items() gives the pairs |
| Set("emma") | set("emma") sorted(set("emma")) # ['a','e','m'] | lesson 13's vocabulary trick: unique characters, sorted |
| Swift | Python | notes / output |
|---|---|---|
| for x in xs { } | for x in xs: | identical idea |
| for i in 0..<5 { } for i in 1..<4 { } | for i in range(5): # 0,1,2,3,4 for i in range(1, 4): # 1,2,3 | range is end-exclusive, exactly like ..<. range(1, 301) in lesson 9 = epochs 1…300 |
| for (i, ch) in xs.enumerated() | for i, ch in enumerate(xs): | index + element together |
| for (a, b) in zip(xs, ys) | for a, b in zip(xs, ys): | pairwise walk — the book's dot products: for x, w in zip(inputs, weights) |
| for ((x1, x2), y) in data | for (x1, x2), y in data: | tuple unpacking — destructure nested pairs right in the loop head (lessons 9–10's training data) |
| while true { … break } | while True: … break | lesson 14's generation loop |
The single most Swift-foreign thing in the book. A comprehension builds a collection from a loop, written inside the brackets. Read it back-to-front: "for each x … produce this expression".
| Swift | Python | actual output |
|---|---|---|
| (0..<5).map { $0 * $0 } | [x*x for x in range(5)] | [0, 1, 4, 9, 16] |
| (0..<10).filter { $0 % 2 == 0 } | [x for x in range(10) if x % 2 == 0] | [0, 2, 4, 6, 8] |
| (0..<5).map { $0*$0 } .reduce(0, +) | sum(x*x for x in range(5)) | 30 |
| Dictionary(uniqueKeysWithValues: "ab".enumerated() .map { ($1, $0) }) | {ch: i for i, ch in enumerate("ab")} | {'a': 0, 'b': 1} |
That last one is lesson 13's stoi table — character → ID. When a comprehension confuses you, unroll it mentally into a plain for loop with .append(…); they're the same machine.
| Swift | Python | notes |
|---|---|---|
| func sigmoid(_ z: Double) -> Double { 1 / (1 + exp(-z)) } | def sigmoid(z): return 1 / (1 + math.exp(-z)) | def, colon, indent; return is always explicit; no types written |
| { v in -v } // closure | lambda v: -v | a one-expression anonymous function |
| xs.sorted { … } xs.max { … } | sorted(xs, key=lambda v: -v) max(emb, key=lambda w: cos(t, emb[w])) | key= says "rank by this value" — lesson 15 finds the nearest word with exactly this |
global state (lesson 14) declares that a function assigns to a variable living outside it — Swift closures capture outer variables automatically; Python makes you say it for writes.
| Swift | Python | notes |
|---|---|---|
| if z > 0 { } else { } | if z > 0: … else: … | no parens, no braces, colon + indent |
| let s = a > 0.5 ? "YES" : "no" | s = "YES" if a > 0.5 else "no" | ternary reads middle-out: value-if-true, condition, value-if-false (lesson 2) |
| Swift | Python | notes |
|---|---|---|
| import Foundation exp(-z); sqrt(x) | import math math.exp(-z); math.sqrt(x) | stdlib math lives behind a prefix |
| // lessons 11–12 only | import torch import torch.nn as nn | as makes a short alias — like Swift's typealias, for a whole module |
No classes, no inheritance, no decorators, no async, no exceptions handling, no type hints. If you can read everything above, you can read 100% of the Python in lessons 1–19 — verified by scanning every snippet. To go beyond reading into fluent writing, the official Python tutorial is the canonical next step; chapters 3–5 cover this entire page.
Open Google Colab, make a new notebook, and retype any table row — guess the output before running. Retyping beats rereading; that's lesson-zero of this whole book.