A tour of the Python 3.14 standard library by job: the modules and calls you reach for before
installing anything. Dates live in Dates & times, re and text in
Strings, asyncio and threads in
Async & concurrency.
Files & paths
pathlib.Path replaces most of os.path. Open text files with an explicit encoding="utf-8".
light tuple with names (typing.NamedTuple for types)
Other
Use
heapq.heappush(h, x), heappop(h)
min-heap on a list; 3.14 adds heappush_max and friends
heapq.nlargest(n, it, key=)
top n without sorting everything
bisect.insort(a, x), bisect_left(a, x)
keep a sorted list sorted
from collections import ChainMap, Counter, defaultdict, dequewords = "the cat and the hat and the bat".split()print(Counter(words).most_common(2))# [('the', 3), ('and', 2)]by_len: defaultdict[int, list[str]] = defaultdict(list)for w in words: by_len[len(w)].append(w)recent: deque[str] = deque(maxlen=3)recent.extend(["a", "b", "c", "d"]) # deque(['b','c','d'])defaults = {"port": "8000", "debug": "0"}env = {"debug": "1"}cfg = ChainMap(env, defaults)print(cfg["port"], cfg["debug"]) # 8000 1
itertools
All return lazy iterators; wrap in list() to see them.
Function
Example
Result
chain(a, b)
chain([1], [2, 3])
1 2 3
chain.from_iterable(xs)
flatten one level
islice(it, stop)
islice(count(), 3)
0 1 2
batched(it, n, strict=False)
batched("abcde", 2)
('a','b') ('c','d') ('e',)
pairwise(it)
pairwise([1, 2, 3])
(1,2) (2,3)
groupby(it, key)
consecutive runs (sort by the key first)
(key, group) pairs
accumulate(it, fn)
accumulate([1, 2, 3])
1 3 6
product(a, b)
product("ab", [0, 1])
nested loops
permutations(it, r), combinations(it, r)
combinations("abc", 2)
ab ac bc
zip_longest(a, b, fillvalue=)
zip that pads
takewhile(p, it), dropwhile(p, it)
prefix / rest
count(start, step), cycle(it), repeat(x, n)
infinite (or n) streams
starmap(fn, pairs)
starmap(pow, [(2, 3)])
8
tee(it, n)
split one iterator into n
from itertools import batched, groupby, pairwiserows = [("a", 1), ("a", 2), ("b", 3)]for key, grp in groupby(rows, key=lambda r: r[0]): print(key, [n for _, n in grp]) # a [1, 2], b [3]deltas = [b - a for a, b in pairwise([1, 4, 9, 16])]chunks = list(batched(range(7), 3))print(deltas, chunks) # [3, 5, 7] [(0,1,2),(3,4,5),(6,)]
functools & operator
functools
Use
@cache
unbounded memo on hashable args
@lru_cache(maxsize=256)
bounded memo; f.cache_info(), f.cache_clear()
@cached_property
computed once per instance
partial(f, *args, **kw)
pre-fill arguments; 3.14 Placeholder skips a position
When you need checksums for a folder, or want to find duplicate files.
import hashlibfrom collections import defaultdictfrom pathlib import Pathdef sha256(path: Path) -> str: with path.open("rb") as f: return hashlib.file_digest(f, "sha256").hexdigest()def duplicates(root: Path) -> list[list[Path]]: by_hash: defaultdict[str, list[Path]] = defaultdict(list) for dirpath, dirnames, filenames in root.walk(): dirnames[:] = [d for d in dirnames if d[0] != "."] for name in filenames: p = dirpath / name by_hash[sha256(p)].append(p) return [ps for ps in by_hash.values() if len(ps) > 1]for group in duplicates(Path(".")): print(*group, sep=" == ")
Read and write CSV as dicts
When a spreadsheet export needs filtering or reshaping before it goes somewhere else.
import csvfrom pathlib import Pathsrc, dst = Path("people.csv"), Path("adults.csv")src.write_text("name,age\nada,36\nkid,9\n", encoding="utf-8")with src.open(newline="", encoding="utf-8") as f: rows = list(csv.DictReader(f)) # list[dict[str, str]]adults = [r for r in rows if int(r["age"]) >= 18]with dst.open("w", newline="", encoding="utf-8") as f: w = csv.DictWriter(f, fieldnames=["name", "age"]) w.writeheader() w.writerows(adults)print(dst.read_text(encoding="utf-8"))
Atomic file write
When a crash halfway through writing must never leave a truncated config or state file.
import osimport tempfilefrom pathlib import Pathdef write_atomic(path: Path, text: str) -> None: fd, tmp = tempfile.mkstemp(dir=path.parent) try: with os.fdopen(fd, "w", encoding="utf-8") as f: f.write(text) f.flush() os.fsync(f.fileno()) # data on disk first os.replace(tmp, path) # atomic on one filesystem except BaseException: os.unlink(tmp) raisewrite_atomic(Path("state.json"), '{"ok": true}\n')
Run a command and capture output
When a script shells out to git, ffmpeg or bun and needs the output or a clear failure.
import shutilimport subprocessdef git(*args: str) -> str: if shutil.which("git") is None: raise RuntimeError("git is not installed") try: res = subprocess.run( ["git", *args], capture_output=True, text=True, check=True, timeout=30, ) except subprocess.CalledProcessError as err: msg = err.stderr.strip() raise RuntimeError(f"git {args[0]}: {msg}") from err return res.stdout.strip()print(git("rev-parse", "--short", "HEAD"))
Memoise expensive calls
When a pure function gets called repeatedly with the same arguments (parsing, lookups, recursion).
from functools import cache, lru_cache@cachedef fib(n: int) -> int: return n if n < 2 else fib(n - 1) + fib(n - 2)@lru_cache(maxsize=1024)def normalize(sku: str) -> str: return sku.strip().upper().replace(" ", "-")print(fib(200))normalize("ab 1")normalize("ab 1") # served from the cacheprint(normalize.cache_info()) # hits=1 misses=1 ...
Arguments must be hashable (no lists or dicts). On methods, @cache keeps self alive; use
@cached_property or a module-level function instead.
Local SQLite with a context manager
When an app needs a small durable store with zero setup.
import sqlite3from contextlib import closingwith closing(sqlite3.connect("app.db")) as conn: conn.row_factory = sqlite3.Row with conn: # commit, or roll back on error conn.execute( "CREATE TABLE IF NOT EXISTS todo" "(id INTEGER PRIMARY KEY, title TEXT, done INT)" ) conn.executemany( "INSERT INTO todo(title, done) VALUES (?, ?)", [("write sheet", 1), ("ship", 0)], ) rows = conn.execute( "SELECT id, title FROM todo WHERE done = ?", (0,) ).fetchall() for row in rows: print(row["id"], row["title"])
with conn: manages the transaction but does not close the connection; closing() does. Always
pass values as ? parameters, never with f-strings.