Python JSON in Depth
A round trip saves data and loads it back again. Some values change in silence on that trip.
Keys change in silence
This dict has number keys. Watch what the keys become after the round trip.
import json
data = {1: "one", 2: "two"}
text = json.dumps(data, sort_keys=True)
print(text)
loaded = json.loads(text)
print(list(loaded.keys()))JSON spelling
JSON has its own spelling for three Python values. The words are all small letters.
import json
print(json.dumps({"ready": True, "done": False, "extra": None}))Help dumps with default
dumps cannot save a set by itself. A default function gets called for such values, and sorted turns the set into a list.
import json
print(json.dumps({"nums": {3, 1, 2}}, default=sorted))Build objects with object_hook
object_hook runs on each dict that loads makes. This one turns a point dict into a tuple.
import json
def to_point(data):
if "x" in data and "y" in data:
return (data["x"], data["y"])
return data
point = json.loads('{"x": 2, "y": 3}', object_hook=to_point)
print(point)Catch bad JSON
Text that is not valid JSON raises JSONDecodeError. A try block can catch it and carry on.
import json
try:
json.loads("{not json}")
except json.JSONDecodeError:
print("That text is not valid JSON.")Example
import json
from dataclasses import dataclass
@dataclass
class Book:
title: str
pages: int
def encode_book(obj):
if isinstance(obj, Book):
return {"title": obj.title, "pages": obj.pages, "kind": "book"}
raise TypeError("Not a Book")
def decode_book(data):
if data.get("kind") == "book":
return Book(data["title"], data["pages"])
return data
book = Book("Dune", 412)
text = json.dumps(book, default=encode_book, sort_keys=True)
print(text)
back = json.loads(text, object_hook=decode_book)
print(back)
print(back == book)Key points
- JSON object keys are always strings
- A number key in a dict comes back as a string after a round trip
- Round trip: save data and load it back again
- Use default to tell dumps how to save an object it does not know
- Use object_hook to turn each loaded dict into your own kind of object
- JSONDecodeError: the error raised when text is not valid JSON
- JSON spells its special values true, false and null
- Python spells its special values True, False and None
In this example, Book is a dataclass with a title and a page count. dumps meets a Book and does not know it. The default function encode_book turns the Book into a plain dict. A kind field marks the dict as a book. The JSON text prints with sorted keys. loads then runs decode_book on the dict. The kind field tells it to build a Book again. The last line proves the round trip kept the data.
Note
A set is not valid JSON data on its own.
A default function can turn it into a list first.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Python Playground
Exercise
You load JSON that came from the dict {1: "one"}. What is the key in the loaded dict?