Working with JSON

JSON is just text — and it maps directly onto dicts and lists

JSON (JavaScript Object Notation) is a plain-text format for structured data — and not coincidentally, it’s shaped almost exactly like Python’s own dicts and lists, which is a large part of why it’s the default format for API requests/responses, config files, and tool-call arguments alike:

{
    "name": "research_agent",
    "model": "claude-sonnet",
    "temperature": 0.7,
    "tags": ["search", "reasoning"]
}

(a plain JSON file, shown for reference — not Python code, not run live)

Read that side by side with a Python dict literal and the resemblance is immediate:

  • JSON objects become dicts
  • JSON arrays become lists
  • JSON strings/numbers/booleans/null become str/int or float/ bool/None

The json module (part of the standard library — no install needed) converts between the two directly.

Reading JSON from a file: json.load

Try it — edit and run

json.load(f) takes an already-open file object (note: not a filename — you still need with open(...) from the previous section to get one) and parses its entire contents into ordinary Python data — here, a dict, since the file’s top level is a JSON object. Once parsed, it’s just a regular dict — every dict operation from the data structures lesson applies normally.

Writing JSON to a file: json.dump

The reverse direction — converting Python data into JSON text and writing it to a file — uses json.dump:

import json

config = {
    "name": "research_agent",
    "model": "claude-sonnet",
    "temperature": 0.7,
    "tags": ["search", "reasoning"],
}

with open("config.json", "w") as f:
    json.dump(config, f, indent=2)

(writes a file — not run live in this format, but produces the exact file shown at the top of this section, reformatted with indent=2)

indent=2 is optional but worth using by default for anything a human might read later — without it, json.dump writes the most compact form possible, all on one line, which is valid JSON but painful to read.

json.loads / json.dumps — the string versions

Sometimes JSON arrives as a string you already have in memory — an API response body, for instance — rather than something sitting in a file. json.loads (load string) and json.dumps (dump to a string) do the same conversions, without any file involved:

Try it — edit and run

The naming is consistent across all four: load/dump work with an already-open file object; loads/dumps work with a plain string — the s suffix specifically flags “string,” not “load safely” or anything else. It’s easy to reach for the wrong one out of habit, so it’s worth checking which you actually have (a file object, or a string) before picking which function to call.

When the JSON itself is malformed: JSONDecodeError

Parsing can fail — the text might not actually be valid JSON at all (a trailing comma, a missing quote, truncated data from a network error):

Try it — edit and run

JSONDecodeError is a normal exception, catchable exactly like any other from the Python setup lesson’s error handling concept:

Try it — edit and run

This matters specifically because JSON so often arrives from somewhere you don’t control — a file someone else edited by hand, a flaky network response — so treating parsing as something that can fail, rather than assuming it always succeeds, is the realistic default here.

Check your understanding
1/5

What Python type does a top-level JSON object ({...}) become once parsed?