ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 34

  1. Blog

ast.literal_eval vs json.loads: Localhost Lab

Aditya Challa·1 October 2026·3 min read

Summary
On this page
  1. Intro — what this post promises
  2. Arms
  3. Lab topology
  4. Lead table (p50 ops/s)
  5. Reading it for SRE work
  6. When literal\_eval is still right
  7. Interchange vs debug dumps
  8. Pitfalls
  9. Reproduce
  10. Limits
  11. Takeaway

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

ArmPattern
json.loads objectcompact JSON
literal_eval objectPython repr
list of 100 intsboth parsers
nested dict/listboth parsers

Seven rounds, p50. Wire sizes: JSON 119 B, repr 138 B.


Lab topology

n=20000 · 7 rounds · p50
metric: ops/s = n / p50_s

Script: lab-evidence/137-literal-eval-vs-json/results/run_lab.py.


Lead table (p50 ops/s)

Armops/s
json.loads object531562
literal_eval object36193
json.loads list100204844
literal_eval list10011490
json.loads nested192005
literal_eval nested6216

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, never eval.
  • 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 eval because 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

python3 lab-evidence/137-literal-eval-vs-json/results/run_lab.py

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.

pythonjsonastliteral_evalparsingperformancebenchmarkingsecurity

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.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

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

On this page

  1. Intro — what this post promises
  2. Arms
  3. Lab topology
  4. Lead table (p50 ops/s)
  5. Reading it for SRE work
  6. When literal\_eval is still right
  7. Interchange vs debug dumps
  8. Pitfalls
  9. Reproduce
  10. Limits
  11. Takeaway
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove