Why do int keys of a python dict turn into strings when using json.dumps?
Question:
According to this conversion table, Python ints get written as JSON numbers when serialized using the JSON module–as I would expect and desire.
I have a dictionary with an integer key and integer value:
>>> d = {1:2}
>>> type(d.items()[0][0])
<type 'int'>
>>> type(d.items()[0][1])
<type 'int'>
When I use the json module to serialize this to a JSON string, the value is written as a number, but the key is written as a string:
>>> json.dumps(d)
'{"1": 2}'
This isn’t the behavior I want, and it seems particularly broken since it breaks json.dumps/json.loads round-tripping:
>>> d == json.loads(json.dumps(d))
False
Why does this happen, and is there a way I can force the key to be written as a number?
Answers:
The simple reason is that JSON does not allow integer keys.
object
{}
{ members }
members
pair
pair , members
pair
string : value # Keys *must* be strings.
As to how to get around this limitation – you will first need to ensure that the receiving implementation can handle the technically-invalid JSON. Then you can either replace all of the quote marks or use a custom serializer.
If you really want to, you can check keys for being convertable to integers again using:
def pythonify(json_data):
for key, value in json_data.iteritems():
if isinstance(value, list):
value = [ pythonify(item) if isinstance(item, dict) else item for item in value ]
elif isinstance(value, dict):
value = pythonify(value)
try:
newkey = int(key)
del json_data[key]
key = newkey
except TypeError:
pass
json_data[key] = value
return json_data
This function will recursively cast all string-keys to int-keys, if possible. If not possible the key-type will remain unchanged.
I adjusted JLT’s example below slightly. With some of my huge nested dictionaries that code made the size of the dictionary change, ending with an exception. Anyhow, credit goes to JLT!
def pythonify(json_data):
correctedDict = {}
for key, value in json_data.items():
if isinstance(value, list):
value = [pythonify(item) if isinstance(item, dict) else item for item in value]
elif isinstance(value, dict):
value = pythonify(value)
try:
key = int(key)
except Exception as ex:
pass
correctedDict[key] = value
return correctedDict
According to this conversion table, Python ints get written as JSON numbers when serialized using the JSON module–as I would expect and desire.
I have a dictionary with an integer key and integer value:
>>> d = {1:2}
>>> type(d.items()[0][0])
<type 'int'>
>>> type(d.items()[0][1])
<type 'int'>
When I use the json module to serialize this to a JSON string, the value is written as a number, but the key is written as a string:
>>> json.dumps(d)
'{"1": 2}'
This isn’t the behavior I want, and it seems particularly broken since it breaks json.dumps/json.loads round-tripping:
>>> d == json.loads(json.dumps(d))
False
Why does this happen, and is there a way I can force the key to be written as a number?
The simple reason is that JSON does not allow integer keys.
object
{}
{ members }
members
pair
pair , members
pair
string : value # Keys *must* be strings.
As to how to get around this limitation – you will first need to ensure that the receiving implementation can handle the technically-invalid JSON. Then you can either replace all of the quote marks or use a custom serializer.
If you really want to, you can check keys for being convertable to integers again using:
def pythonify(json_data):
for key, value in json_data.iteritems():
if isinstance(value, list):
value = [ pythonify(item) if isinstance(item, dict) else item for item in value ]
elif isinstance(value, dict):
value = pythonify(value)
try:
newkey = int(key)
del json_data[key]
key = newkey
except TypeError:
pass
json_data[key] = value
return json_data
This function will recursively cast all string-keys to int-keys, if possible. If not possible the key-type will remain unchanged.
I adjusted JLT’s example below slightly. With some of my huge nested dictionaries that code made the size of the dictionary change, ending with an exception. Anyhow, credit goes to JLT!
def pythonify(json_data):
correctedDict = {}
for key, value in json_data.items():
if isinstance(value, list):
value = [pythonify(item) if isinstance(item, dict) else item for item in value]
elif isinstance(value, dict):
value = pythonify(value)
try:
key = int(key)
except Exception as ex:
pass
correctedDict[key] = value
return correctedDict