Her aunt wants the day's numbers, not a screenshot of them. JSON turns a Python dictionary into text another program can read back. What survives that round trip, and what quietly changes type?
JSON is a text format for structured data. APIs and configuration files use it constantly. Python's json module converts between JSON text and dictionaries, lists, strings, numbers, booleans, and None. You will also validate decoded JSON before indexing and produce stable output.
Parse and serialise
json.loads(text) parses a JSON string into Python values. json.dumps(value) turns a Python value into JSON text. The s in loads and dumps stands for string; load and dump work with file objects.
import json
raw = '{"drink": "latte", "price": 4.5}'
data = json.loads(raw)
print(data["drink"])
print(json.dumps(data))Text to Python and back
Walk nested data
A JSON object becomes a dictionary; a JSON array becomes a list. Chain keys and indexes to reach a nested value. Loop over a list of records when you need to summarise every item.
import json
raw = '{"items": [{"name": "latte"}, {"name": "tea"}]}'
data = json.loads(raw)
for item in data["items"]:
print(item["name"])Nested records
Keep output readable
json.dumps accepts indent for pretty printing and sort_keys for stable key order. These options are useful for configuration files and debugging. They do not change the underlying values.
import json
data = {"b": 2, "a": 1}
print(json.dumps(data, indent=2, sort_keys=True))Readable JSON
Validate shape before indexing
json.loads() validates JSON syntax, not your schema. A decoded value can be a list instead of a dictionary, or a field can be missing. Check the container type, then each key, before indexing.
import json
raw = '{"order": {"items": [{"name": "latte", "qty": 2}]}}'
data = json.loads(raw)
order = data.get("order", {})
items = order.get("items", [])
print(isinstance(items, list), len(items))
if items and isinstance(items[0], dict):
print(items[0].get("name", "unknown"))Syntax is not a schema
Make JSON output stable
sort_keys=True makes output stable across runs, and indent=2 makes it readable. Use compact output for machines and indented output for logs or teaching examples. ensure_ascii=False keeps non-English text readable when that is desired.
import json
payload = {"total": 12.0, "items": ["latte", "tea"], "note": "café"}
print(json.dumps(payload, sort_keys=True))
print(json.dumps(payload, indent=2, sort_keys=True, ensure_ascii=False))Stable key order and readable Unicode
JSON is not Python
JSON supports objects, arrays, strings, numbers, booleans, and null. Python tuples become arrays, integer keys become strings, and None becomes null. That means a round trip may not preserve the original Python types. Dump with sort_keys=True for stable output, and use ensure_ascii=False when you want readable non-ASCII text.
import json
payload = {"count": 2, "tags": ("tea", "latte"), "note": None}
text = json.dumps(payload, sort_keys=True)
print(text)
print(json.loads(text))A tuple becomes an array
Key points
- json.loads parses a string; json.dumps serialises to a string.
- JSON objects map to dictionaries and JSON arrays map to lists.
- Use chained keys and indexes to reach nested values.
- indent and sort_keys make JSON easier to inspect.
- Valid JSON syntax does not guarantee the shape your code expects.
- JSON has fewer types than Python; a round trip can change containers.
Common mistakes
- Calling json.load on a string instead of json.loads.
- Using single quotes in JSON text; JSON strings require double quotes.
- Forgetting that JSON null becomes Python None.
- Indexing a decoded object before checking that it is a dictionary.
- Assuming a tuple or an integer key survives json.dumps() and json.loads().
Parse a JSON object with an items list, sum the numeric values, and print the total.
Try it yourself
Change the values, predict the output, then run the code. The Python runtime is downloaded the first time you press Run, so the first run can take a few seconds.
Practice this lesson
12 questions with immediate explanations.