Hands-on csv.reader vs str.split vs DictReader lab: real rows/s on a quoted-field CSV fixture (pandas-free parse), measured on Linux localhost for SREs.
4 min read
Parsing CSV without pandas: is naive str.split(',') worth it over csv.reader, and what does csv.DictReader cost? This lab times rows/s on a generated fixture with quoted commas on Linux localhost.
Related links:
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Fixtures under lab-evidence/78-csv-reader-vs-split/results/fixture_*.csv. Affiliates: 0. No pandas.
Verdict up front (10 000 rows consume): split ~5422k/s vs csv.reader ~2345k (~2.31×) vs DictReader ~948k (reader ~2.47× DictReader). But split had the wrong field count on ~62% of rows — fast and wrong. Prefer csv.reader / DictReader.
| Arm | Pattern |
|---|---|
csv.reader | list or consume |
str.split(',') | per line — breaks quotes |
csv.DictReader | row dicts by header |
| DictReader from file | includes local open |
Script: lab-evidence/78-csv-reader-vs-split/results/run_lab.py.
| Arm | n=1 000 | n=10 000 | n=50 000 |
|---|---|---|---|
| split | 5536k | 5422k | 5166k |
| csv.reader | 2459k | 2345k | 2338k |
| DictReader | 988k | 948k | 903k |
| Fixture | split rows with wrong arity |
|---|---|
| 1 000 | 61.8% |
| 10 000 | 62.3% |
| 50 000 | 62.7% |
Quoted "hello, ""world"" #i" style notes are normal CSV — split cannot win.
Building a dict per row costs about ~2.5× vs csv.reader lists at n=10 k. File open on the same fixture was nearly free vs in-memory StringIO (mem÷file ~1.02×).
csv.reader is the correct default for row lists.DictReader buys named columns for ~2.5× time — often worth it in app code.CSV exporters quote when a field contains the delimiter, quotes, or newlines. Real billing/export files do this constantly. A microbench on comma-only synthetic rows would crown split and teach the wrong lesson. This fixture forces ~60%+ arity failures so the speed story cannot hide the correctness story.
At 50 k rows, building a Python list of every row slows csv.reader more than streaming consume. If you aggregate on the fly (counts, filters), iterate the reader without retaining all rows. DictReader amplifies that allocation cost because each row is a new dict.
line.split(',') on vendor CSV — silent column shifts.newline='' when opening files for csv module.| Need | Prefer |
|---|---|
| Correct CSV rows | csv.reader |
| Header → dict rows | csv.DictReader |
| Truly delimiter-only, no quotes | split (rare; document assumption) |
| Heavy analytics | pandas/polars (out of scope) |
Always decide whether the first line is a header. DictReader assumes it; csv.reader does not. Mixing next(reader) skips with split-based header parsing is a common off-by-one source when rewriting parsers. Keep one code path.
Evidence: /workspace/lab-evidence/78-csv-reader-vs-split/results/.
Don’t split production CSV. On this box split looked ~2.3× faster than csv.reader at 10 k rows while corrupting ~62% of records; DictReader traded ~2.5× for ergonomics. Correctness first — then measure.
Lab evidence
Lab 1 Oct 2026 IST. Python 3.13.5. n=10k consume: split 5422k rows/s vs csv.reader 2345k (2.31x) vs DictReader 948k (reader2.47x DictReader). split wrong field count ~62% on quoted fixture. Affiliates: 0. Evidence: lab-evidence/78-csv-reader-vs-split/.
Hands-on platform.platform vs os.uname host inventory lab: real ops/s plus cache notes, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20264 min read
Hands-on signal SIGUSR1 vs threading.Event wakeup lab: real p50 latency in microseconds, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20264 min read
Hands-on cmath vs math.hypot magnitude ops lab: real ops/s for abs, polar, and phase, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20263 min read