Plate 34
ast.literal_eval vs json.loads: Localhost Lab
Aditya Challa3 min read
Intro — what this post promises
Safe parsing with json.loads vs ast.literal_eval. This lab reports ops/s on Linux localhost for an object, a 100-int list, and a nested structure — both arms avoid eval.
Related links:
- selectors vs select localhost lab
- dataclass asdict vs vars localhost lab
- tracemalloc snapshot localhost lab
- sqlite3 vs shelve localhost lab
- gc collect cost localhost lab
- path read text vs open localhost lab
- intenum vs int localhost lab
- cmath vs math hypot localhost lab
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. JSON text from json.dumps; Python text from repr() for literal_eval. Objects equal (equal=True).
Verdict up front (n=20000): object — json ~531562 ops/s vs literal_eval ~36193; nested — json ~192005 vs literal_eval ~6216.
Arms
| Arm | Pattern |
|---|---|
| json.loads object | compact JSON |
| literal_eval object | Python repr |
| list of 100 ints | both parsers |
| nested dict/list | both parsers |
Seven rounds, p50. Wire sizes: JSON 119 B, repr 138 B.
Lab topology
Script: lab-evidence/137-literal-eval-vs-json/results/run_lab.py.
Lead table (p50 ops/s)
| Arm | ops/s |
|---|---|
| json.loads object | 531562 |
| literal_eval object | 36193 |
| json.loads list100 | 204844 |
| literal_eval list100 | 11490 |
| json.loads nested | 192005 |
| literal_eval nested | 6216 |
JSON led every column — roughly 14.7× on the object arm.
Reading it for SRE work
- Inter-service / config-on-disk → JSON (speed + ecosystem).
- Must accept Python literals from trusted tools (tuples, single quotes) →
ast.literal_eval, nevereval. - Agent status blobs already JSON → do not “simplify” to literal_eval.
- Both are safe relative to
eval; neither replaces a schema validator.
When literal_eval is still right
Admin pastes, debug __repr__ dumps, and some legacy .cfg fragments ship Python literals. literal_eval is the correct safe parser there — just budget ~36193 ops/s vs JSON’s ~531562 on similar data.
Nested structures widen the gap (json ~192005 vs literal_eval ~6216). Prefer JSON for anything on a hot ingest path.
Interchange vs debug dumps
JSON is the right default for anything that crosses a process or language boundary: ~531562 ops/s here beats literal_eval’s ~36193, and every other service already speaks it. Keep ast.literal_eval in the toolbox for trusted Python-literal pastes and __repr__ forensics — especially lists of ints where the gap grew to json ~204844 vs literal_eval ~11490.
Put a hard byte cap in front of either parser when input can be attacker-controlled; safe parsing is not the same as cheap parsing of huge trees.
If a runbook still says “just eval the blob,” replace that line with literal_eval or JSON and re-test — correctness first, then the ops/s table above.
Pitfalls
- Using
evalbecause literal_eval “felt slow.” - Feeding JSON (
true/null) to literal_eval. - Feeding Python repr with single quotes to json.loads.
- Skipping size limits on untrusted input (both can allocate big trees).
Reproduce
Evidence: summary.json, summary.txt.
Limits
One Linux box. CPython parsers only. Not orjson/ujson, not YAML.
Document which parser each config path uses so on-call does not “fix” a slow ingest by swapping JSON for repr dumps under pressure.
Measure your own payload shapes before rewriting parsers in a hot path.
Takeaway
json.loads ~531562 ops/s vs ast.literal_eval ~36193 on a small object. Prefer JSON for interchange; keep literal_eval for trusted Python-literal text only.
Lab evidence
What I found running this
Ran the literal_eval-vs-json lab on Linux localhost today with Python 3.13.5, seven rounds and p50 ops/s. On the object arm, json.loads measured ~531562 ops/s versus ast.literal_eval ~36193; nested text measured ~192005 versus ~6216. JSON led every column; both arms avoided eval. Affiliates: 0.
Related links
Plate 76
html.parser vs regex Tag Strip: Localhost Lab
1 Oct 2026
Plate 68
gc.collect Cost Empty vs Cycles: Localhost Lab
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.
Observability & SRE · 1 Oct 2026
Plate 77
fractions.Fraction vs float: Localhost Lab
Hands-on fractions.Fraction vs float for exact ratios: real ops/s and exactness checks, measured on Linux localhost today in this hands-on lab for SREs.
1 Oct 2026