Loops, functions and types work in Python much as they do in any language you already know. ML code adds a handful of Python habits it uses on every page, plus one piece of setup: a per project. This chapter covers both, fast, by contrast with other languages.
A is like a Go slice or a JavaScript array: ordered, growable, repeats allowed. A maps keys to values, like a map or hash table elsewhere, and a keeps each value once. A builds any of the three in one expression, with the loop, the filter and the append folded together.
# a list keeps order and repeats
runs = ['a', 'b', 'a']
runs.append('d')
runs['a', 'b', 'a', 'd']# a dict maps keys to values
lr = {'a': 0.1, 'b': 0.05}
lr['c'] = 0.01
lr{'a': 0.1, 'b': 0.05, 'c': 0.01}# a set keeps each value once, in no guaranteed order
{3, 1, 3, 2}{1, 2, 3}[x * x for x in range(6) if x % 2 == 0][0, 4, 16]One small job puts several of these to work: reading a CSV of training runs by hand. names the file, splits the header from the other lines, and a turns each line into a .
from pathlib import Pathpath = Path('data') / 'runs.csv'text = path.read_text()header, *lines = text.splitlines()columns = header.split(',')rows = [dict(zip(columns, line.split(','))) for line in lines]rows[0]['loss'] + rows[1]['loss']losses = {row['run']: float(row['loss']) for row in rows}import pandas as pddf = pd.read_csv(path)df['loss'][0] + df['loss'][1]path
PosixPath('data/runs.csv')The / operator joins path parts. On Windows the same line makes a WindowsPath.
Every value came back a string, which is why step six joins two losses as text instead of adding them, with no error. pandas, in Chapter 4, reads a file like it into typed columns in one call.
An puts expressions inside a string, with an optional format after a colon: {loss:.2f} prints two decimals. In a function’s parameters, collects extra positional arguments into a tuple and collects extra keyword arguments into a . At a call the stars work the other way round, so train(**config) feeds a config straight into a function.
loss = 0.4213
f'loss {loss:.2f} after {3 * 2} epochs''loss 0.42 after 6 epochs'def log(*values, **fields):
return values, fields
log(1, 2, lr=0.1)((1, 2), {'lr': 0.1})def train(lr, epochs):
return f'lr={lr}, epochs={epochs}'
config = {'lr': 0.1, 'epochs': 5}
train(**config)'lr=0.1, epochs=5'A is a struct, as in Go or C, with its constructor, printing and equality written for you. Its fields carry , and here Python parts ways with statically typed languages: no compiler checks them, and Python doesn’t either when the code runs. This is the easy one to get wrong. Run('b', '0.05') builds without complaint, and the string shows up later: as a TypeError if you’re lucky, or, as below, as a wrong answer with no error.
from dataclasses import dataclass
@dataclass
class Run:
name: str
lr: float
Run('a', 0.1)Run(name='a', lr=0.1)Run('a', 0.1) == Run('a', 0.1)True# the hint says float, but nothing checks it
bad = Run('b', '0.05')
bad.lr * 2'0.050.05'A works like Go’s defer or Java’s try-with-resources, in block form: with path.open() as f: closes the file when the block ends, even if it raises. A makes its values one at a time, only when asked, so a file bigger than memory can be read line by line. Once it has run out it stays empty, and a second loop over it gets nothing, with no error.
from pathlib import Path
path = Path('data/runs.csv')
with path.open() as f:
header = f.readline()
header, f.closed('run,lr,loss\n', True)def losses(path):
with path.open() as f:
next(f) # skip the header
for line in f:
yield float(line.split(',')[2])
g = losses(path)
next(g)0.42list(g)[0.31, 0.58]list(g)[]Last, the setup every later chapter runs in. A is a folder of packages for one project, like node_modules with its own python. installs the pinned versions into it. , from Astral, can do the same job, and its docs describe it as extremely fast.
python3 -m venv ~/.venvs/python-for-ml # or: uv venv ~/.venvs/python-for-ml
source ~/.venvs/python-for-ml/bin/activate
pip install -r requirements.txt # or: uv pip install -r requirements.txt
You will also meet the , a document of code cells you run one at a time. This course uses plain .py files and pytest instead, because they diff cleanly and run anywhere.
The habit to keep: convert what comes from a file or a caller to the type you mean before you use it. only say what you meant; float() and int() make it so.
Homework
The packet first checks that your has Python 3.12 or newer and every pinned version. Then you read a CSV of training runs into , and with , fill in a and an , and finish with a , , and .
Chapter 1 workbook
Unzip, follow the README once to set up, then run pytest until it's green.