A trimmed plan for a 90‑minute hands‑on session using this repository. Each item includes a short goal, file reference, estimated time, and a minimal solution sketch.
Suggested flow (target ~80–90 min including brief discussion):
- Hello CLI (6m)
- Parse + stats (12m)
- Primes in range (10m)
- Groupby decades (12m)
- Dataclass Point (12m)
- JSON averaging (12m) Stretch) Reduce gcd/lcm or Welford mini (10–15m)
Prereqs
- Python 3.9+ (3.11+ ideal). Optional: create env from
environment.yml. - Run from repo root; paths are relative to
source_code/presentation/....
- Goal: greet a name and print Python version.
- Start from:
presentation/fundamentals/hello_world.py - Steps: add
argparse --name; printsys.version.split()[0]. - Sketch:
#!/usr/bin/env python3 import argparse, sys p = argparse.ArgumentParser() p.add_argument('--name', default='World') a = p.parse_args() print(f"Hello, {a.name}!") print(f"Python {sys.version.split()[0]}")
- Goal: min/max/mean and invalid count from text file.
- Data:
presentation/fundamentals/data/measurement.txt - Steps: strip, skip empty/#, parse float; count failures.
- Sketch:
good = []; bad = 0 for ln in open(path): s = ln.strip() if not s or s.startswith('#'): continue try: good.append(float(s)) except ValueError: bad += 1 mmin, mmax = min(good), max(good) mean = sum(good)/len(good)
- Goal: emit primes in
[lo, hi)or firstNprimes. - Start from:
presentation/iterators/primes.py - Steps: add
--lo --hi --count(mutually exclusive hi/count); stop accordingly. - Sketch:
import math def is_prime(n): return n>1 and all(n%d for d in range(2, int(math.sqrt(n))+1)) def primes(): yield 2; k = 3 while True: if is_prime(k): yield k k += 1
- Goal: group objects by computed key with
groupby. - Pattern: like
presentation/iterators/people.py. - Steps: define
Person(name, age); sort byage//10;groupbyby decade and count. - Sketch:
from itertools import groupby class Person: def __init__(s,n,a): s.name=n; s.age=a people = [Person('A',23), Person('B',35), Person('C',31)] people.sort(key=lambda p: p.age//10) for dec, grp in groupby(people, key=lambda p: p.age//10): grp = list(grp); print(dec, len(grp))
- Goal: add validation and helpers to
Point. - Start from:
presentation/oop/point_01.py - Steps:
__post_init__numeric check;translate(dx,dy);midpoint(other). - Sketch:
@dataclasses.dataclass class Point: x: float; y: float def __post_init__(self): for v in (self.x, self.y): if not isinstance(v, (int,float)): raise TypeError def translate(self, dx, dy): return Point(self.x+dx, self.y+dy) def midpoint(self, o): return Point((self.x+o.x)/2, (self.y+o.y)/2)
- Goal: mean and median age; handle nulls; optional
--min-age. - Start from:
presentation/data-formats/average_age.pyandpeople.json. - Sketch:
import json, statistics, argparse p = argparse.ArgumentParser(); p.add_argument('--min-age', type=float) a = p.parse_args() ages = [r.get('age') for r in json.load(open('people.json'))] ages = [x for x in ages if isinstance(x,(int,float))] if a.min_age is not None: ages = [x for x in ages if x >= a.min_age] print({'mean': statistics.fmean(ages), 'median': statistics.median(ages)})
S1) Reduce gcd/lcm (8–10m)
- Start:
presentation/operators-functools/reduce.py - Sketch:
from functools import reduce from math import gcd def lcm(a,b): return abs(a*b)//gcd(a,b) if a and b else 0 def gcd_list(xs): return reduce(gcd, xs) def lcm_list(xs): return reduce(lcm, xs)
S2) Welford streaming stats (12–15m)
- Refs:
source_code/welford_algorithm.ipynb,hands-on/data/measurement.txt - Sketch:
import math class Stats: def __init__(s): s.n=0; s.mean=0.0; s.M2=0.0 def add(s,x): s.n+=1; d=x-s.mean; s.mean+=d/s.n; s.M2+=d*(x-s.mean) def stdev(s): return math.sqrt(s.M2/(s.n-1)) if s.n>1 else 0.0