Code of the Day
IntermediateData I/O & manipulation

Working with JSON

Parse and serialise JSON — the wire format of the web — with Python's json module.

PythonIntermediate8 min read
Recommended first
By the end of this lesson you will be able to:
  • Parse a JSON string or file with json.loads() and json.load()
  • Serialise Python objects to JSON with json.dumps() and json.dump()
  • Use indent and sort_keys to produce readable output
  • Handle JSONDecodeError for invalid input
  • Explain the Python-to-JSON type mapping and the datetime caveat

is the dominant format for data exchange on the web — REST APIs return it, configuration files use it, services pass it in messages. Python's standard-library json module converts between JSON text and Python objects in both directions.

Parsing JSON

Two functions read JSON:

  • json.loads(s) — parses a string (the s is for string).
  • json.load(f) — reads from a file object.
import json

text = '{"name": "Alice", "scores": [91, 85, 78]}'
data = json.loads(text)

print(data["name"])       # "Alice"
print(data["scores"][0])  # 91

The result is a plain Python dict, list, string, int, float, bool, or None — you work with it just like any other Python object.

# Reading from a file
with open("config.json") as f:
    config = json.load(f)

Serialising to JSON

Two matching functions write JSON:

  • json.dumps(obj) — returns a JSON string.
  • json.dump(obj, f) — writes to a file object.
user = {"name": "Bob", "age": 25, "active": True}
print(json.dumps(user))
# '{"name": "Bob", "age": 25, "active": true}'

Notice that Python True becomes JSON true — the module handles capitalisation automatically.

Readable output with indent and sort_keys

By default json.dumps produces a compact single line. For human-readable output (config files, debugging), pass indent:

print(json.dumps(user, indent=2, sort_keys=True))

sort_keys=True alphabetises the keys, which makes diffs cleaner when the data is version-controlled.

Python — editable, runs in your browser

Round-tripping and nested structures

JSON handles arbitrary nesting — dicts of lists of dicts — and Python mirrors that directly. A common pattern is reading, transforming, and writing back:

with open("records.json") as f:
    records = json.load(f)

for r in records:
    r["score"] = r["score"] * 1.1   # bump every score by 10 %

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

Handling errors

If the JSON text is malformed, json.loads raises json.JSONDecodeError (a subclass of ValueError). Always wrap untrusted input:

import json

raw = '{"name": "Alice", broken}'   # invalid JSON

try:
    data = json.loads(raw)
except json.JSONDecodeError as e:
    print(f"Bad JSON at line {e.lineno}: {e.msg}")

The datetime caveat

Python's datetime is not a JSON-native type — trying to serialise one raises a TypeError. The standard workaround is to convert to an ISO string before dumping:

from datetime import datetime
import json

event = {"at": datetime.now().isoformat(), "type": "login"}
print(json.dumps(event))   # works — isoformat() returns a plain string

The JSON type mapping: dict → object, list/tuple → array, str → string, int/float → number, True/False → true/false, None → null. Anything else (datetime, custom objects, sets) needs a manual conversion before serialising.

Where to go next

Next: Data transformation patterns — sorting, grouping, counting, and reshaping data with Python's built-in tools.

Finished reading? Mark it complete to track your progress.

On this page