Plate 23
textwrap.fill vs Manual Wrap: Localhost Lab
Aditya Challa4 min read
Intro — what this post promises
Wrapping a long paragraph to a fixed width: textwrap.fill, textwrap.wrap + join, a manual word-pack, or a hard character chunk. This lab reports wraps/s on generated fixtures (width 72) on Linux localhost.
Related links:
- str translate vs replace localhost lab
- csv reader vs split localhost lab
- secrets vs urandom localhost lab
- bytesio vs spooled tempfile localhost lab
- json dumps compact vs indent localhost lab
- decimal vs float sum localhost lab
- weakref vs dict cache localhost lab
- glob vs rglob vs walk localhost lab
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Fixtures under lab-evidence/89-textwrap-fill-vs-manual/results/fixture_*.txt. Affiliates: 0. No Docker.
Verdict up front (1000 words): manual word-pack ~9632 wraps/s vs textwrap.fill ~1240 (~7.77×); hard chunk ~147102 but breaks mid-word. fill and manual agreed on 88 lines for this fixture.
Arms
| Arm | Pattern |
|---|---|
textwrap.fill | stdlib paragraph fill |
textwrap.wrap + join | same engine, list then join |
| manual word-pack | accumulate words until width |
| hard chunk | slice every width chars (breaks words) |
Lab topology
Script: lab-evidence/89-textwrap-fill-vs-manual/results/run_lab.py.
Lead table — wraps/s (p50)
| Fixture | fill | wrap+join | manual pack | hard chunk |
|---|---|---|---|---|
| 200 words | 6071 | 6034 | 43508 | 509423 |
| 1000 words | 1240 | 1285 | 9632 | 147102 |
| 5000 words | 252 | 260 | 1929 | 32842 |
Line counts (fill vs manual): 200→18/18; 1000→88/88; 5000→440/440.
Reading it
- Manual word-pack ~7.77× faster than
textwrap.fillon the 1000-word fixture — fill does more (expand tabs, sentence handling options, robustness). fill≈wrap+join — pickfillfor a string;wrapwhen you want a list of lines.- Hard chunk is not wrapping — it is the fastest and the wrong product for prose.
- Prefer
textwrapin application code unless profiling shows wrap in a hot loop; then a tight word-pack may be enough if you accept fewer features.
What textwrap buys
textwrap handles edge cases this manual pack skips: replace_whitespace, drop_whitespace, break_long_words, break_on_hyphens, max_lines / placeholder, and indent variants (fill/indent/shorten). Throughput is not the only scoreboard.
Fixture note
Paragraphs are synthetic word streams (no punctuation). That favors simple packers and keeps fill/manual line counts aligned here. Real prose with long URLs/hyphens can diverge — re-bench on your corpus.
When manual pack is enough
CLI help text, log pretty-printers, and offline report generators often need “width 72, break on spaces” and nothing else. A 20-line word-pack then wins on simplicity and speed. The moment you need hyphen breaks, reserved indentation, or max_lines with an ellipsis, stay on textwrap.
fill vs wrap in practice
textwrap.fill(text, width) is sugar for "\n".join(textwrap.wrap(...)) with the same kwargs. This lab’s fill vs wrap+join arms stayed within noise (~1240 vs ~1286 wraps/s at 1000 words). Choose based on whether you want a string or a list of lines for further processing (prefixing, numbering, boxed output).
Throughput vs features
The ~7–8× manual-pack win is real on synthetic ASCII words. It disappears as a product concern if wrap runs once per HTTP response and your handler already spends milliseconds on templates or DB. Profile first; micro-optimizing wrap is rarely the SRE win.
Pitfalls
- Shipping hard-chunk “wrap” to UI users (broken words).
- Re-wrapping on every keystroke without caching.
- Assuming manual pack matches
textwrapfor tabs / CJK / combining characters. - Optimizing wrap before measuring — usually I/O or templating dominates.
Reproduce
Evidence includes fixture_words_*.txt, summary.json.
Limits
One Linux box. ASCII-ish synthetic words. Width fixed at 72. Not terminal East-Asian width tables.
Takeaway
On 1000-word paragraphs, manual word-pack ~9632 wraps/s beat textwrap.fill ~1240 (~7.77×) with the same line count on this fixture. Default to textwrap.fill for correct, featureful wrapping; reach for a manual pack only when a profiler says so — and never confuse hard chunking with wrapping.
Lab evidence
What I found running this
Lab 1 Oct 2026 IST. Python 3.13.5. width=72. 1000 words: fill 1240/s; manual 9632/s (~7.77x); hard chunk 147102/s breaks words. fill and manual agreed on 88 lines for this fixture. Affiliates: 0. Evidence: lab-evidence/89-textwrap-fill-vs-manual.
Related links
Plate 12
islice vs list Slice Windows: Localhost Lab
Hands-on itertools.islice vs list slice window lab: real ops/s taking ranges from sequences, measured on Linux localhost in this hands-on lab for SREs.
Observability & SRE · 1 Oct 2026
Plate 07
heapq.merge vs sorted(chain): Localhost Lab
Hands-on heapq.merge vs sorted(chain) multi-way merge: real records/s on pre-sorted lists, measured on Linux localhost today in this hands-on lab for SREs.
Observability & SRE · 1 Oct 2026
Plate 88
mmap Write vs pwrite Region: Localhost Lab
Hands-on mmap MAP_SHARED write+msync vs pwrite region update: real MB/s with durability labels, measured on Linux localhost in this hands-on lab for SREs.
Observability & SRE · 1 Oct 2026