JSON is a text format for nested data. Nested means a value holds other values, such as a list inside an object. A JSON object looks like a Python dict.
json.loads turns JSON text into Python objects. Look at the types. A JSON number stays a number, and JSON null becomes None:
json.loads on one orderworked example
import json
text = '{"order_id": 101, "customer_id": 1, "status": "paid", "amount": 40.0}'
order = json.loads(text)
print(order)
print(type(order).__name__, order["amount"])
pending = json.loads('{"order_id": 105, "amount": null}')
print(pending)
Result · 3 rows
| output |
|---|
| {'order_id': 101, 'customer_id': 1, 'status': 'paid', 'amount': 40.0} |
| dict 40.0 |
| {'order_id': 105, 'amount': None} |
type(order).__name__ gives the name of the type: dict. Unlike CSV, JSON keeps numbers as numbers. Order 105 has null, so its amount is None.
Here is orders.json. It holds a list of orders under the key "orders":
The file orders.jsonworked example
{"orders": [
{"order_id": 101, "customer_id": 1, "status": "paid", "amount": 40.0},
{"order_id": 105, "customer_id": 3, "status": "pending", "amount": null}
]}
It holds two of the six orders. It is one document: one object that holds a list.
Read the file with read_text(), then json.loads. (json.load reads from an open file. json.loads reads from a text.) Then use the key "orders":
Read orders.jsonworked example
import json
from pathlib import Path
text = Path("orders.json").read_text(encoding="utf-8")
data = json.loads(text)
print(list(data))
for order in data["orders"]:
print(order["order_id"], order["amount"])
Result · 3 rows
| output |
|---|
| ['orders'] |
| 101 40.0 |
| 105 None |
list(data) gives the keys of the dict. Then the loop goes through the list of orders.
If the sender changes the format, json.loads may return a list, not a dict. Check before you use it. isinstance(payload, dict) is True only for a dict:
Check the shapeworked example
import json
payload = json.loads('[{"order_id": 101}]')
if not isinstance(payload, dict):
print("rejected: expected an object, got", type(payload).__name__)
Result · 1 row
| output |
|---|
| rejected: expected an object, got list |
This payload is a list, so it is rejected with a reason. Without the check, payload["orders"] would crash.
A JSON document is read as a whole. One wrong character, and nothing is read. Here the closing brace is missing:
One wrong characterworked example
import json
try:
json.loads('{"order_id": 101')
except json.JSONDecodeError as error:
print(error)
Result · 1 row
| output |
|---|
| Expecting ',' delimiter: line 1 column 17 (char 16) |
The error says where Python gave up. You get no order at all. The next section shows a format that avoids this.