简体   繁体   中英

Deserialize JSON to Object

I'm working on a trivial problem here to deserialize some JSON (I cannot change the format, it's not a service I created) into Python objects. I've managed to do the conversion using lambda's, but I'd like to use an object_hook now, to see if the it's possible to do a conversion using the json.loads method. However, that's where I'm failing right now, and I was wondering if someone could point me in the right direction.

This is the code I currently have:

import json

class Light:
    def __init__(self, id, name):
        self.id = id
        self.name = name

response = '{"1": {"name": "bedroom"}, "2": {"name": "kitchen"}}'

def object_decoder(obj):
    return Light(......)

print json.loads(response, object_hook=object_decoder)

As you can see, the response is one document with two keys, named 1 and 2. It would be nice if I can make the the code work in a way that the json.loads would return two Light objects, but at the moment, I'm stuck, and I don't know how to iterate over response to make this work.

object_hook won't help you, since you have id and name on the different levels in the json string:

object_hook, if specified, will be called with the result of every JSON object decoded and its return value will be used in place of the given dict.

Let's see why object_hook won't help. If you print objects that are coming to the object_decoder function, you'll see that it is going up from the deep, like this:

{u'name': u'bedroom'}
{u'name': u'kitchen'}
{u'1': None, u'2': None}
None

This means that you cannot join object_decoder calls in order to produce a Light instance.

How about using custom JSONDecoder class instead:

import json


class Light:
    def __init__(self, id, name):
        self.id = id
        self.name = name


response = '{"1": {"name": "bedroom"}, "2": {"name": "kitchen"}}'


class Decoder(json.JSONDecoder):
    def decode(self, s):
        obj = super(Decoder, self).decode(s)
        return [Light(id=k, name=v['name']) for k, v in obj.iteritems()]


lights = json.loads(response, cls=Decoder)
print lights  # prints [<__main__.Light instance at 0x9c3b50c>, <__main__.Light instance at 0x9c3b56c>]
print [light.__dict__ for light in lights]  # prints [{'id': u'1', 'name': u'bedroom'}, {'id': u'2', 'name': u'kitchen'}]

This is actually the same as making json.loads() and then instantiate classes after.

If you are able to change the format of the string, I suggest you use jsonpickle . I've founded it perfect for this sort of thing.

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