Hands-on itertools.batched vs manual list-slice chunking: real items/s batching sequences, measured on Linux localhost today in this hands-on lab for SREs.
3 min read
Split a sequence into fixed-size batches via itertools.batched vs manual list slices / islice chunking. This lab reports items/s on Linux localhost.
Related links:
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. batched is stdlib since 3.12.
Verdict up front (100 k items / batch 100): batched consume ~274.18 Mitems/s; batched→list ~247.69; list slices ~242.25; islice chunks ~104.07. Prefer batched for clarity on iterables; slices fine for concrete lists.
| Arm | Pattern |
|---|---|
list(batched(seq, n)) | stdlib → list of tuples |
consume batched | no outer list |
| list comprehension slices | classic |
islice loop | iterable DIY |
| while + append slices | imperative |
Script: lab-evidence/120-itertools-batched-vs-chunk/results/run_lab.py.
| Arm | Mitems/s |
|---|---|
| batched consume | 274.18 |
| batched → list | 247.69 |
| list slices | 242.25 |
| while append slices | 229.33 |
| islice manual | 104.07 |
| Config | batched consume | list slices |
|---|---|---|
| 10k / 256 | 296.61 | 424.81 |
| 100k / 100 | 274.18 | 242.25 |
| 100k / 1000 | 326.94 | 344.78 |
batched yields tuples. Wrap list(chunk) only if a callee requires lists — SQL executemany usually accepts tuples.
Both styles emit a final short batch. If your protocol forbids short batches, pad or drop explicitly.
batched.islice chunkers unless you need custom policies.Network APIs, executemany, and bulk inserts all prefer finite pages. Chunking wrong (off-by-one, dropped remainders, huge last page) causes retries and timeouts. batched makes the page loop obvious in code review.
list(batched(...)) retains every page. For multi-million row exports, iterate for page in batched(rows, n): sink(page) without collecting. The consume arm in this lab models that path.
Lab 109 measured skipping to a mid-list window. This lab tiles the whole sequence. Reusing an islice-based chunker is fine functionally but trailed batched and slices here (~104 Mitems/s vs ~240+ Mitems/s at 100 k/100).
batched on Python ≤3.11 without a polyfill.Evidence: summary.json, summary.txt.
Document batch size next to timeout and payload limits so operators can tune pages without reading the chunker implementation.
One Linux box. Integer lists in RAM. Not async or multiprocess batching.
Keep the comparison honest: measure your resource type (dummy vs FD) before optimizing.
At 100 k / 100, batched ~274.18 Mitems/s matches list slices ~242.25; DIY islice ~104.07 trails. Default to itertools.batched.
Lab evidence
Ran the batching benchmark on Linux localhost with Python 3.13.5. Measured 7 rounds and used p50 for items/s across 10k and 100k item sequences. At 100k/batch 100, batched consume measured about 274.18 Mitems/s versus 242.25 for list slices and 104.07 for islice. The result matched the expected iterable-versus-list tradeoff.
Hands-on gc.collect cost empty vs cyclic garbage lab: real collect latency plus reclaim counts, measured on Linux localhost today in this lab for SREs.
Hands-on1 Oct 20264 min read
Hands-on contextlib.ExitStack vs nested with and manual close: real cycles/s for N resources, measured on Linux localhost in this hands-on lab for SREs.
Hands-on1 Oct 20263 min read
Hands-on sqlite3 vs shelve local KV store lab: real insert/get ops/s plus file sizes, measured on Linux localhost today in this hands-on lab for SREs.
Hands-on1 Oct 20264 min read