简体   繁体   中英

Python: Loading a dictionary with numeric keys from a JSON string (with double quoted keys)

>>> import json
>>> example = { 1: "banana", 2: "apple"}
>>> example
{1: 'banana', 2: 'apple'}
>>> json_example = json.dumps(example)
>>> json_example
'{"1": "banana", "2": "apple"}'
>>> from_str=json.loads(json_example)
>>> from_str
{'1': 'banana', '2': 'apple'}

My problem is quite simple, but I can't find a straightforward solution...

From a json encoded string (here json_example ), where keys represent numeric values, but are double quoted (because JSON standard allows only double quoted string as property key), I want to load a dict where keys are numeric values.

But json.loads returns a dict where keys are strings. How can I get the keys as numeric values?

EDIT:

A one-liner like the one proposed by @not_speshal would be perfectly ok in most cases. But the context of this problem is a Django form (to read a json string provided by the user). I am looking for a solution which could involve a JSON decoder. So I can pass it as an argument to the Django forms.JSONField class, to avoid subclassing this class and writing a lot of Django-specific code.

The most straightforward way I can think of is to go over the loaded dict and parse the str keys into int s like @not_speshal suggests in their comment .

{int(k): from_str[k] for k in from_str}

You could use the object_hook argument to json.loads() if you wanted a single function call to do the trick. This doesn't save any computations because the object is still read as a dict with str keys that you then convert to int .

From the docs :

object_hook is an optional function that will be called with the result of any object literal decoded (a dict ). The return value of object_hook will be used instead of the dict . This feature can be used to implement custom decoders (eg JSON-RPC class hinting).

example = { 1: "banana", 2: "apple"}
json_example = json.dumps(example)

def parse_int_keys(dct):
    rval = dict()
    for key, val in dct.items():
        try:
            # Convert the key to an integer
            int_key = int(key)
            # Assign value to the integer key in the new dict
            rval[int_key] = val
        except ValueError:
            # Couldn't convert key to an integer; Use original key
            rval[key] = val
    return rval

from_str = json.loads(json_example, object_hook=parse_int_keys)
# from_str is now 
# {1: 'banana', 2: 'apple'}

The advantage of this approach is that it also works on nested dicts without having to write any more code:

obj = {'a': 1, 'b': {1: 'abc'}, 0: [1, 2, 3], '1234': 'Hi!'}
json.loads(json.dumps(obj), object_hook=parse_int_keys)
# Output: 
# {'a': 1, 'b': {1: 'abc'}, 0: [1, 2, 3], 1234: 'Hi!'}

However, note that keys that were originally strings that can be parsed into integers (such as '1234' in my example above) will still be converted to integers because we have no way of distinguishing between the two cases.

The simplest solution would be to create an empty dict and fill it while iterating through the first one and cast the keys to int values?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM