Python JSON: dumps, loads, Type Changes, and Common Errors
JSON is a text format for structured data, and Python's json module turns dictionaries and lists into JSON text (dumps) and JSON text back into dictionaries and lists (loads). A round trip does not always return the same thing you started with: tuples come back as lists, and number keys come back as strings. The module reference documents both. Every example below was run in Python 3.13, and the output shown is what it printed. The reference was read in October 2026.
1. dumps and loads: Python to text and back
The "s" in dumps and loads stands for string. dumps returns a string, and loads takes one.
import json
order = {"id": 7, "items": ["tea", "cake"], "paid": True, "note": None, "total": 12.5}
text = json.dumps(order)
print(text)
print(type(text))
{"id": 7, "items": ["tea", "cake"], "paid": true, "note": null, "total": 12.5}
<class 'str'>
True became true and None became null. The reference gives the full conversion table:
| Python | JSON |
|---|---|
| dict | object |
| list, tuple | array |
| str | string |
| int, float | number |
| True / False | true / false |
| None | null |
Going the other way:
back = json.loads(text)
print(back)
print(back == order)
print(back["items"][1])
{'id': 7, 'items': ['tea', 'cake'], 'paid': True, 'note': None, 'total': 12.5}
True
cake
Here the round trip returned an equal dictionary, because every value was a type JSON represents exactly.
2. Making it readable
indent adds line breaks and spacing, and sort_keys=True orders the keys. Both are options the reference lists for pretty printing.
print(json.dumps(order, indent=2, sort_keys=True))
{
"id": 7,
"items": [
"tea",
"cake"
],
"note": null,
"paid": true,
"total": 12.5
}
Without indent, everything is on one line. The reference also shows separators=(',', ':') for the most compact output.
3. What changes on the round trip
JSON has arrays but no tuples, so a tuple is written as an array and comes back as a list:
data = {"point": (3, 4), "ok": True, "none": None}
print(json.dumps(data))
print(json.loads(json.dumps(data)))
{"point": [3, 4], "ok": true, "none": null}
{'point': [3, 4], 'ok': True, 'none': None}
Keys have a similar rule. The reference states that keys in JSON are always strings, so converting a dictionary with non-string keys and back can produce a dictionary that is not equal to the original:
keys = {1: "one", 2: "two"}
print(json.dumps(keys))
print(json.loads(json.dumps(keys)))
print(json.loads(json.dumps(keys)) == keys)
{"1": "one", "2": "two"}
{'1': 'one', '2': 'two'}
False
If you use IDs as dictionary keys and save them to JSON, convert them back with int() after loading.
4. Non-English text
By default ensure_ascii is true, and the reference says the output then escapes all non-ASCII characters. The text is still valid and loads back correctly, but it is hard to read. Set it to false to keep the characters:
print(json.dumps({"city": "Zürich"}))
print(json.dumps({"city": "Zürich"}, ensure_ascii=False))
{"city": "Z\u00fcrich"}
{"city": "Zürich"}
5. Reading the errors
Invalid JSON raises json.JSONDecodeError. These three strings are common mistakes when writing JSON by hand:
for bad in ["{'a': 1}", '{"a": 1,}', '{"a": True}']:
try:
json.loads(bad)
except json.JSONDecodeError as e:
print(bad, "->", e)
{'a': 1} -> Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
{"a": 1,} -> Illegal trailing comma before end of object: line 1 column 8 (char 7)
{"a": True} -> Expecting value: line 1 column 7 (char 6)
JSON requires double quotes, does not allow a trailing comma, and spells booleans in lowercase. The error message gives the line and column where parsing stopped, which is where to look first. The exact wording of these messages can differ between Python versions.
Values JSON has no type for raise a TypeError when you write them:
json.dumps({"when": {1, 2}})
TypeError: Object of type set is not JSON serializable
Convert a set with sorted() or list() before dumping it. The reference also describes a default= function for teaching dumps how to handle your own types.
6. Files: dump and load
The tutorial's input and output chapter has a short section on saving structured data with the json module. Without the "s", json.dump(obj, file) writes to an open file and json.load(file) reads from one:
with open("order.json", "w", encoding="utf-8") as f:
json.dump(order, f, indent=2)
with open("order.json", encoding="utf-8") as f:
print(json.load(f) == order)
True
7. Key takeaways
dumpsandloadswork with strings;dumpandloadwork with open files.- Dict maps to object, list and tuple to array,
Nonetonull,Truetotrue. - Tuples come back as lists, and non-string dictionary keys come back as strings.
- Use
indentandsort_keys=Truefor readable output;ensure_ascii=Falsekeeps non-English characters. JSONDecodeErrormessages give the line and column; double quotes, no trailing commas and lowercase booleans are the usual fixes.- Sets and custom objects raise
TypeErrorunless you convert them first.
Sources
More on work & tech from other topics
- Fake Check and Reshipping Job Scams: How They Work · Remote Work Notes
- Can You Record a Zoom or Teams Meeting Without Telling People? Washington and Florida Law · AI at Work, Plainly
- IFERROR vs IFNA, Which Errors Should You Hide? · Spreadsheet Diary