The standard library toolkit
collections, itertools, functools, hashlib, uuid, os and sys — the batteries that ship with Python.
Why this matters in AI / ML / GenAI
Counting label frequencies, grouping records, caching embeddings, fingerprinting datasets, and generating request ids are daily tasks. Each has a one-line standard-library answer that most people reimplement badly.
1. Read
Understand the idea in plain English first.
2. Run
Load any example into the compiler and press Run.
3. Change
Edit one value, rerun, and learn from the output.
collections
Counter— frequency counting with.most_common(n). Perfect for label distributions, token frequencies, and spotting class imbalance.defaultdict— a dict that creates missing values automatically, so grouping needs noif key not in ddance.namedtuple— a lightweight immutable record with named fields.deque— a double-ended queue with O(1) appends and pops at both ends, and amaxlenthat discards old items. Ideal for rolling windows and sliding-window metrics.OrderedDict— rarely needed now that regular dicts preserve insertion order.
functools and itertools
functools: lru_cache / cache for memoizing pure functions, partial to pre-fill arguments, wraps for decorators, reduce for custom folds, and cached_property for expensive attributes computed once per instance.
itertools: chain, islice, groupby (requires sorted input — the number one gotcha), product for hyperparameter grids, combinations and permutations, cycle, count, and accumulate for running totals.
Both modules are implemented in C, so they are faster than hand-written equivalents as well as shorter.
Identity, hashing, and the environment
uuid — uuid.uuid4() for request ids and run ids. Unique without coordination between machines.
hashlib — sha256 to fingerprint a dataset, cache key, or prompt. A stable fingerprint lets you prove two runs used identical data. Never use md5 for security, and never hash passwords with a plain digest.
os / sys — os.getenv for configuration, os.cpu_count() for worker sizing, sys.argv for CLI arguments (though argparse is better), sys.version_info for version checks, and sys.exit(1) to signal failure to CI.
pathlib, json, csv, tempfile, shutil cover the rest of everyday file work.
Hands-on practice
Compiler on the left. Examples on the right.
On desktop, keep the compiler beside the examples. On mobile, the same blocks stack cleanly. Pick an example, try it in the compiler, then change one small thing.
Analyse a batch of model calls
Live Python compiler
Try it — in-browser Python
Add more calls and watch the Counter and rolling window update.
Code editor
Output
Python runs in your browser. First run downloads the runtime.
Press Run (or Ctrl+Enter) to execute.
Runs CPython in your browser. NumPy, pandas, scikit-learn and Matplotlib load on demand. Charts appear below the output. No input(), no GPU, no network installs.
Clear code examples
Every example is copy-ready. Use Try in compiler when you want to experiment without scrolling around.
Example
Counter for label distribution
Class imbalance shows up immediately.
from collections import Counter
labels = ["positive"] * 70 + ["negative"] * 25 + ["neutral"] * 5
counts = Counter(labels)
print(counts)
print("most common:", counts.most_common(2))
total = sum(counts.values())
for label, n in counts.most_common():
bar = "#" * (n // 2)
print(f"{label:9} {n:3} ({n / total:5.1%}) {bar}")
print("\nimbalance ratio:", round(max(counts.values()) / min(counts.values()), 1), ": 1")
print("token frequency:", Counter("the cat sat on the mat".split()).most_common(2))Example
defaultdict and deque
Grouping without key checks, and a fixed-size rolling window.
from collections import defaultdict, deque
records = [
("mlops", "doc-1"), ("rag", "doc-2"),
("mlops", "doc-3"), ("agents", "doc-4"), ("rag", "doc-5"),
]
grouped = defaultdict(list)
for topic, doc in records:
grouped[topic].append(doc)
for topic, docs in grouped.items():
print(f"{topic:8} -> {docs}")
window = deque(maxlen=5)
print("\nrolling mean of last 5 latencies:")
for latency in [100, 120, 900, 130, 110, 105, 98]:
window.append(latency)
print(f" add {latency:3} -> window={list(window)} mean={sum(window) / len(window):.1f}")Example
namedtuple and cached results
lru_cache turns a repeated computation into a lookup.
import functools
from collections import namedtuple
Prediction = namedtuple("Prediction", ["doc_id", "label", "score"])
preds = [
Prediction("d1", "positive", 0.91),
Prediction("d2", "negative", 0.44),
]
for p in preds:
print(f"{p.doc_id}: {p.label} ({p.score:.2f})")
print("as dict:", preds[0]._asdict())
@functools.lru_cache(maxsize=256)
def expensive_embed(text):
print(" computing:", text)
return sum(ord(c) for c in text) % 9973
print("\nfirst call :", expensive_embed("python"))
print("second call:", expensive_embed("python"), "(cached)")
print("cache stats:", expensive_embed.cache_info())Example
itertools groupby and accumulate
groupby needs sorted input — that is the classic mistake.
import itertools
rows = [
{"model": "mini", "tokens": 500},
{"model": "large", "tokens": 1200},
{"model": "mini", "tokens": 300},
{"model": "large", "tokens": 900},
]
rows.sort(key=lambda r: r["model"]) # required before groupby
for model, group in itertools.groupby(rows, key=lambda r: r["model"]):
items = list(group)
print(f"{model:6} calls={len(items)} tokens={sum(i['tokens'] for i in items)}")
daily = [120, 340, 88, 502]
print("\nrunning total:", list(itertools.accumulate(daily)))
print("grid combos :", len(list(itertools.product([1e-5, 2e-5], [16, 32], [3, 5]))))Example
uuid, hashlib, and environment
Request ids and dataset fingerprints in three lines.
import hashlib
import json
import os
import sys
import uuid
request_id = str(uuid.uuid4())
print("request id:", request_id, "| short:", request_id[:8])
dataset = [{"text": "sample a", "label": 1}, {"text": "sample b", "label": 0}]
fingerprint = hashlib.sha256(json.dumps(dataset, sort_keys=True).encode()).hexdigest()
print("dataset fingerprint:", fingerprint[:16])
prompt = "Summarise the quarterly report"
cache_key = hashlib.sha256(f"gpt-4.1-mini|0.0|{prompt}".encode()).hexdigest()[:20]
print("cache key:", cache_key)
os.environ.setdefault("LOG_LEVEL", "INFO")
print("\nlog level :", os.getenv("LOG_LEVEL"))
print("python :", ".".join(map(str, sys.version_info[:3])))
print("cpu count :", os.cpu_count())Takeaways
- Counter for distributions, defaultdict for grouping, deque for rolling windows.
- lru_cache memoizes pure functions; itertools.groupby needs sorted input.
- uuid4 for request ids, sha256 for dataset and cache fingerprints.