CodeKitchen prep
0%
Contest in--:--:--
Python Β· lesson 02/13

🐍Python toolkit for data

⏳ ~20 min

This is the standard library you'll reach for in almost every data problem. Learn these idioms well enough to type them without thinking.

1. Fast input / output

import sys

def main():
    data = sys.stdin.buffer.read().split()   # all tokens as bytes; fastest
    # or: lines = sys.stdin.read().splitlines()   # when lines contain spaces
    n = int(data[0])
    nums = list(map(int, data[1:1 + n]))
    out = []
    for x in nums:
        out.append(str(x * 2))
    sys.stdout.write("\n".join(out) + "\n")   # ONE write at the end

main()   # wrapping in a function makes local variable lookups faster

input() plus print() for each of 10⁢ lines can take seconds. Read everything at once and write once. If lines may contain spaces, use splitlines(), not split().

2. collections: the data engineer's best friends

from collections import Counter, defaultdict, deque, OrderedDict

c = Counter(["a", "b", "a", "c", "a"])
c.most_common(2)            # [('a', 3), ('b', 1)]  (ties keep first-seen order, so sort explicitly if needed)
c["zzz"]                    # 0, never KeyError

groups = defaultdict(list)  # group-by in one line
for user, amount in rows:
    groups[user].append(amount)

totals = defaultdict(float)
for user, amount in rows:
    totals[user] += amount

window = deque(maxlen=3)    # sliding window of the last 3 items
window.append(x)            # O(1) at both ends; list.pop(0) is O(n)!

3. Sorting like a pro

rows.sort(key=lambda r: (-r["total"], r["name"]))   # total DESC, name ASC
sorted(ids, key=int)                                 # numeric strings
sorted(words, key=str.lower)                         # case-insensitive
# Sort is STABLE: sort by the secondary key first, then by the primary key
rows.sort(key=lambda r: r["name"]); rows.sort(key=lambda r: r["dept"])

# can't negate a string? sort twice or use reverse=True on that pass
from operator import itemgetter
rows.sort(key=itemgetter("dept", "name"))

4. itertools & heapq

from itertools import groupby, chain, islice, accumulate, combinations, pairwise
import heapq

# groupby only groups CONSECUTIVE equal keys, so sort first!
data.sort(key=lambda r: r["user"])
for user, grp in groupby(data, key=lambda r: r["user"]):
    grp = list(grp)

list(accumulate([3, 1, 4]))        # running sum [3, 4, 8]
list(pairwise([1, 5, 6]))          # [(1, 5), (5, 6)]  (Python 3.10+): consecutive diffs
heapq.nlargest(3, items, key=lambda x: x[1])  # top-K in O(n log k)
heapq.merge(sorted_a, sorted_b)    # merge sorted streams lazily (external sort!)

5. Dates and times

from datetime import datetime, date, timedelta, timezone

t = datetime.strptime("2026-10-23 16:00:05", "%Y-%m-%d %H:%M:%S")
t = datetime.fromisoformat("2026-10-23T16:00:05+03:30")   # handles offsets and 'Z' (3.11+)
(t2 - t1).total_seconds()        # use total_seconds(), NOT .seconds (that ignores days!)
d.isoformat(); t.strftime("%Y-%m")       # month bucket
t.date(); t.weekday()            # Monday = 0
t.astimezone(timezone.utc)
date(2026, 10, 23) + timedelta(days=7)

# ISO-8601 strings in the SAME format and timezone sort correctly as plain strings, and that's fast

timedelta.seconds is only the seconds part (0–86399). A two-day gap has .seconds == 0. Always use .total_seconds().

6. JSON, CSV, regex

import json, csv, re, io

obj = json.loads(line)                    # one JSON per line = "JSON Lines"
obj.get("user", {}).get("id")             # safe nested access
json.dumps(obj, ensure_ascii=False, sort_keys=True, separators=(",", ":"))

reader = csv.DictReader(io.StringIO(text))  # handles quoted commas: "Tehran, Iran"
for row in reader: ...                    # values are ALWAYS strings, so convert!
w = csv.writer(sys.stdout); w.writerow(["id", "name"])

LOG = re.compile(r'(?P<ip>\S+) .*?\[(?P<ts>[^\]]+)\] "(?P<method>\w+) (?P<path>\S+)[^"]*" (?P<status>\d{3})')
m = LOG.search(line)
if m: m["path"], int(m["status"])

Never parse CSV with line.split(",") unless the statement guarantees there are no quoted fields. csv handles quoting, embedded commas and escaped quotes for you.

7. Numbers and money

from decimal import Decimal, ROUND_HALF_UP
round(2.5), round(3.5)               # 2, 4   (banker's rounding!)
f"{2.675:.2f}"                        # '2.67' (binary float)
Decimal("2.675").quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)   # 2.68
7 // 2, -7 // 2                        # 3, -4  (floor, not truncation)
float("nan") == float("nan")           # False; use math.isnan
f"{1234567.891:,.2f}"                  # '1,234,567.89'

8. dataclasses & typing (template-style problems)

from dataclasses import dataclass, field
from typing import Iterator

@dataclass(frozen=True)
class Event:
    user_id: str
    ts: int
    kind: str = "view"

def read_events(lines) -> Iterator[Event]:   # generators = streaming, constant memory
    for line in lines:
        u, ts, k = line.rstrip("\n").split("\t")
        yield Event(u, int(ts), k)

9. Input templates for the usual stdin shapes

import sys
lines = sys.stdin.read().splitlines()

# (a) n, then n records
n = int(lines[0]); records = [l.split(",") for l in lines[1:1 + n]]

# (b) records until EOF (skip blank lines, which often hide at the end)
records = [l for l in lines if l.strip()]

# (c) header line + CSV body
import csv, io
rows = list(csv.DictReader(io.StringIO("\n".join(lines))))

# (d) T test cases, each "n" followed by n numbers on one line
it = iter(sys.stdin.read().split())
for _ in range(int(next(it))):
    n = int(next(it)); arr = [int(next(it)) for _ in range(n)]

# (e) first line "n m", then an n Γ— m grid
n, m = map(int, lines[0].split()); grid = [lines[1 + i].split() for i in range(n)]

The token-iterator pattern (d) ignores how the input is split into lines. It's the safest choice when the statement is vague about line breaks.

10. Gotchas that cost points

CodeSurpriseFix
def f(x, acc=[])The default list is shared between callsacc=None, then acc = acc or []
isinstance(True, int)True: bool is a subclass of intCheck bool first
json.loads('{"1": 2}')Keys are always str{int(k): v for k, v in d.items()}
"a,b,".split(",")['a', 'b', ''], with an empty last fieldFilter, or use csv
"a b".split(" ")['a', '', 'b']split() with no argument splits on any whitespace run
sorted([3, None, 1])TypeErrorkey=lambda x: (x is None, x or 0) puts None last
[[0] * m] * nn references to the same row[[0] * m for _ in range(n)]
fns = [lambda: i for i in range(3)]All return 2 (late binding)lambda i=i: i
Deep recursion (DFS on 10⁡ nodes)RecursionError (default limit 1000)Iterative stack, or sys.setrecursionlimit(10**6)
0.1 + 0.2 == 0.3Falsemath.isclose, or Decimal for money
dict modified while iteratingRuntimeErrorIterate over list(d)
s += piece in a 10⁢ loopCan be quadraticCollect in a list, then "".join(parts)

11. Output formatting cookbook

f"{x:.2f}"        # 3.14159 β†’ '3.14'       (always 2 decimals)
f"{x:g}"          # 3.0 β†’ '3', 2.5 β†’ '2.5' (drop trailing zeros)
f"{n:,}"          # 1234567 β†’ '1,234,567'
f"{p:.1%}"        # 0.256 β†’ '25.6%'
f"{n:05d}"        # 42 β†’ '00042'
f"{s:<10}|"      # left-align in 10 chars ('>' right, '^' centre)
print(*row, sep=",")                  # join any values without str() calls
print(json.dumps(obj, sort_keys=True)) # deterministic JSON output
str(True), json.dumps(True)           # 'True' vs 'true': read which one the statement wants
Quiz What does sorted(['10', '9', '2']) return?
Quiz Fastest way to read 10⁢ lines of input in Python?
Quiz round(2.5) in Python 3 is…
Quiz d = json.loads('{"1": 5}'). What does d[1] do?
Quiz def add(x, acc=[]): acc.append(x); return acc. After add(1), what does add(2) return?
🏁 --:--