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?

Asked By: jveldridge

||

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.

Answered By: Sean Vieira

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
Answered By: JLT

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
Answered By: Jonas Melin
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.