Skip to content
Serialization (json.dumps)
step 1/5

Reading — step 1 of 5

Read

~2 min readProduction Concerns

Serialization (json.dumps)

Parsing has an inverse: take an in-memory value, produce JSON text. The shape is the same recursive dispatch, run in reverse:

serialize(v):
    None  -> "null"      True -> "true"      False -> "false"
    number -> str(v)                    # but reject nan/inf!
    string -> quote(v)                  # escaping: the hard part
    list   -> "[" + ",".join(serialize(x) for x in v) + "]"
    dict   -> "{" + ",".join(quote(k) + ":" + serialize(v[k]) for k in sorted(v)) + "}"
    anything else -> error: not serializable

Escaping: the part everyone half-does

The encoder owns the string rules from the escape lesson, in reverse. Must-escape: ", \, and every control character U+0000–U+001F. The idiom is a single pass over characters — it cannot get the ordering wrong:

python

The trap is chained str.replace. If you write s.replace('"', '\\"').replace("\\", "\\\\") the second replace re-escapes the backslashes the first one just inserted, turning say "hi" into say \\"hi\\". Doing backslash first fixes that ordering, but the per-character loop makes the whole bug class impossible — prefer it.

Non-ASCII is a choice: é may be emitted raw (UTF-8) or as \u00e9; both are valid JSON. Python's ensure_ascii=True default escapes everything non-ASCII — safe for legacy transports, bloated for everyone else.

Numbers: two sharp edges

  • nan/inf are unrepresentable. The grammar has no token for them. Python's json.dumps(float("nan")) emits bare NaN by default — output no strict parser will read back. Pass allow_nan=False (or raise, as your serializer should) to fail loudly at write time instead of mysteriously at read time.
  • Emit what the float is, not what looks nice. repr(0.1 + 0.2) is 0.30000000000000004; emitting a prettier 0.3 writes a different number. Round-tripping demands the exact shortest-repr text.

Determinism

{"a":1,"b":2} and {"b":2,"a":1} are the same value but different bytes. Sorting keys (Python: sort_keys=True) makes output a pure function of the value — which is what diffing, caching, hashing, and test snapshots all need. This exercise sorts keys for exactly that reason.

Your exercise

Implement serialize (the input-DSL plumbing is provided). The grader-caught mistakes are all in quote: s:with"quote must print "with\"quote", input with a real tab must print "tab\there", and s:back\slash must print "back\\slash" — one escaped quote, one \t, one doubled backslash; if any of those comes out double-escaped, you have the replace-ordering bug above. Keys sort alphabetically: o:name=alice,age=30 must print {"age":"30","name":"alice"} — and note "30" stays a quoted string, because this DSL makes all object values strings. Compact separators throughout: no spaces after , or :.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…