Silent changes (tuples to lists, int keys to strings) cause subtle bugs after a save and reload.
The encoder translates:
dict→ object,listandtuple→ arraystr→ string,intandfloat→ numberTrue/False→true/false,None→null
Decoding goes the other way, with arrays always becoming list and numbers becoming int if they have no fraction or exponent, otherwise float.
What changes on a round trip:
- Tuples come back as lists.
- Dict keys become strings. JSON object keys must be strings, so
{1: "a"}is written as{"1": "a"}and reads back with key"1".TrueandNonekeys become"true"and"null". Tuple keys raiseTypeError(unlessskipkeys=True, which silently drops them). - Mixed int and str keys that collide after conversion overwrite each other.
What isn't supported at all: set, bytes, datetime, Decimal, custom classes. Encoding them raises TypeError: Object of type set is not JSON serializable. The custom-encoding lessons show how to handle them.
float('nan') and infinities are written as NaN and Infinity, which are not valid JSON; strict parsers in other languages reject them.
Insertion order of dict keys is preserved both ways.
Example
import json
data = {"point": (3, 4), 1: "one", "ids": [1, 2]}
back = json.loads(json.dumps(data))
print(back) # {'point': [3, 4], '1': 'one', 'ids': [1, 2]}
print(back == data) # False
print(json.loads("[1, 1.0, 1e2]")) # [1, 1.0, 100.0]
print(json.dumps({None: 0, True: 1})) # {"null": 0, "true": 1}
for bad in [{1, 2}, b"raw", {(1, 2): "x"}]:
try:
json.dumps(bad)
except TypeError as e:
print(str(e)[:36])
# Object of type set is not JSON seria
# Object of type bytes is not JSON ser
# keys must be str, int, float, bool oRemember
- Tuples become lists and all dict keys become strings
- Sets, bytes, datetime, Decimal and custom objects need explicit handling
- NaN and Infinity are emitted but are not valid JSON
Watch out for
- Saving a dict with int keys and then looking them up with ints after loading.