The Standard Library Modules Worth Knowing Before You pip install
Published:
collections gives you a counting dict, a two-ended queue and a dict with defaults built in; itertools and functools give you lazy iteration and memoisation without hand-rolled loops; datetime, re, random, math/statistics cover the everyday cases directly; argparse and logging replace hand-parsed sys.argv and scattered print calls; pytest (a near-universal third-party addition, not stdlib, but assume it) and typing round out the tools that make code checkable before it runs.Counting, queues, and dicts with defaults, collections
from collections import Counter, defaultdict, deque
words = "the quick brown fox the lazy dog the fox".split()
counts = Counter(words)
print(counts.most_common(2)) # -> [('the', 3), ('fox', 2)]
groups = defaultdict(list)
for w in words:
groups[len(w)].append(w)
print(groups[3]) # -> ['the', 'fox', 'the', 'dog', 'the', 'fox']
dq = deque(maxlen=3) # a bounded ring buffer
for x in range(5):
dq.append(x)
print(dq) # -> deque([2, 3, 4], maxlen=3)
Counter is a dict subclass that never raises KeyError for a missing key, it returns 0, and adds most_common(). defaultdict calls its factory (list, int, set, or any zero-argument callable) the first time a key is missing, which removes the if key not in d: boilerplate covered in dicts and sets. deque is a doubly linked queue with O(1) appends and pops from either end, a plain list is O(n) at the front, and maxlen turns it into a fixed-size sliding window for free.
Iterating without writing the loop, itertools and functools
from itertools import chain, groupby, islice
from functools import lru_cache, partial, reduce
print(list(chain([1, 2], [3, 4]))) # -> [1, 2, 3, 4]
print(list(islice(range(1_000_000), 3))) # -> [0, 1, 2], stops early, no full list built
data = sorted([1, 1, 2, 2, 2, 3])
for key, group in groupby(data):
print(key, list(group))
# -> 1 [1, 1]
# -> 2 [2, 2, 2]
# -> 3 [3]
@lru_cache(maxsize=None)
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
print(fib(35)) # -> 9227465, instant on the second call, exponential-time recursion made linear
add_tax = partial(lambda price, rate: price * (1 + rate), rate=0.2)
print(add_tax(100)) # -> 120.0
print(reduce(lambda acc, x: acc * x, [1, 2, 3, 4], 1)) # -> 24
itertools functions return iterators, not lists, islice on a million-element range never materialises the million elements, echoing the laziness from comprehensions and generators. groupby only groups consecutive runs, so sort first if the groups are not already adjacent. lru_cache memoises a pure function’s return value by its arguments, turning naive recursive Fibonacci from exponential into linear time by never recomputing a call it has already seen. partial fixes some arguments of a callable ahead of time; reduce folds a sequence down to one value, useful, but a plain loop or sum/math.prod is usually more readable for the common cases.
Dates, text patterns, randomness, and numbers
from datetime import date, datetime, timedelta
today = date(2026, 11, 14)
print(today + timedelta(days=30)) # -> 2026-12-14
print(datetime.now().isoformat()) # -> e.g. 2026-11-14T09:12:03.481920
import re
m = re.search(r"(\d{4})-(\d{2})-(\d{2})", "seen on 2026-11-14")
print(m.group(0), m.group(1)) # -> 2026-11-14 2026
print(re.sub(r"\s+", " ", "too many spaces")) # -> too many spaces
import random, math, statistics
random.seed(0)
print(random.choice(["a", "b", "c"])) # -> 'b' (fixed by the seed)
print(math.sqrt(2), math.gcd(48, 18)) # -> 1.4142135623730951 6
print(statistics.mean([1, 2, 3, 4]), statistics.median([1, 2, 3, 4])) # -> 2.5 2.5
Reach for re for patterns, not for structured formats, an email address or a URL has enough edge cases that a dedicated parser beats a regex; re is right for “does this line start with a timestamp”, not “is this a valid email”. random is not cryptographically secure, use the secrets module for tokens or passwords. statistics is exact and pure Python, appropriate for small datasets; anything large belongs in NumPy.
Talking to the system, os and sys
import os, sys
print(os.environ.get("HOME")) # -> /Users/you (or None if unset)
print(sys.argv) # -> ['script.py', 'arg1'] when run as `python script.py arg1`
print(sys.version_info[:2]) # -> (3, 13)
sys.exit(1) # exits the process with status 1
os covers the environment and process-level operations that pathlib does not (environment variables, process IDs, os.cpu_count()); sys covers the interpreter itself, arguments, the module search path, and exit codes that shells and CI systems check.
Parsing arguments and logging properly
import argparse
parser = argparse.ArgumentParser(description="Greet someone")
parser.add_argument("name")
parser.add_argument("--shout", action="store_true")
args = parser.parse_args(["ada", "--shout"])
greeting = f"hello, {args.name}"
print(greeting.upper() if args.shout else greeting) # -> HELLO, ADA
Hand-parsing sys.argv with slicing breaks the moment a flag is optional or reordered; argparse generates --help, type-checks (type=int), and reports usage errors with the right exit code, all from a declarative spec.
import logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
log = logging.getLogger(__name__)
log.info("starting job")
log.warning("retrying, attempt %d", 2) # lazy formatting: only built if WARNING is enabled
logging beats print for anything beyond a throwaway script: it has severity levels you can filter by without editing call sites, timestamps and module names for free, and routes to a file or a log aggregator with the same call sites that write to the console today. print debugging has to be found and deleted; a logging.debug call can just be left there, silent, until the level is turned up.
Testing and types
# test_math_utils.py
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
def test_add_negative():
assert add(-1, 1) == 0
pytest test_math_utils.py discovers any function named test_* with no boilerplate class or registration, a plain assert is the whole API, and a failure prints the actual values on both sides of the comparison automatically.
from typing import Optional
def greet(name: str, times: int = 1) -> list[str]:
return [f"hello, {name}"] * times
def find(items: list[int], target: int) -> Optional[int]:
return items.index(target) if target in items else None
Type hints are not enforced at runtime, greet(5) runs without complaint, but a checker like mypy or pyright catches the mismatch before the code ships, and the annotations double as documentation that cannot silently drift out of date the way a comment can.
re or hand-rolled datetime maths as sufficient for genuinely hard problems like timezone-aware scheduling or RFC-822 email parsing, where a battle-tested third-party library earns its place. The standard library is the first stop, not the only one.Counter replaces a manual for loop plus a defaultdict(int); groupby replaces a hand-written accumulator; lru_cache replaces a manual memoisation dict; reduce replaces an accumulator loop. None of them compute anything a loop could not, they just name the pattern, which makes the intent visible at the call site instead of buried in five lines of bookkeeping.Recap
collections:Counterfor tallies,defaultdictfor grouping,dequeforO(1)operations at either end.itertoolsandfunctoolsreplace loops with named, often lazy, patterns,lru_cachealone turns exponential recursion into linear time.datetime,re,random,math/statisticscover everyday needs; usesecretsinstead ofrandomfor anything security-sensitive.argparsebeats hand-parsingsys.argv;loggingbeatsprintbecause it has levels, timestamps, and routable output.- Type hints are unchecked at runtime, they only help through an external checker like
mypy, but they never silently rot the way a stale comment does.
Next: idiomatic and performant Python, where these building blocks get put to work at speed.
References
- Python documentation.
collections, Container datatypes. - Python documentation.
itertools, Functions creating iterators for efficient looping andfunctools, Higher-order functions. - Python documentation.
datetime,re,random,statistics. - Python documentation.
argparse, Parser for command-line options andlogging, Logging facility for Python. - Python documentation.
typing, Support for type hints. - pytest documentation. Get Started.
- van Rossum, G., Lehtosalo, J., & Langa, Ł. PEP 484, Type Hints, 2014.
