views:

144

answers:

3

Hi, I'm quite new to python (I use python 3), and i'm trying to serialize a class with one string and two lists as members in JSon. I found that there's a json lib in the python standart but it seems that I need to manually implement a serialization method. Is there a JSon encoder where I can simply pass an object, and receive the serialized object as string without having to implement a serialization method. Example:

class MyClass:
    pass

if __name__ == '__main__':
    my_name = "me"
    my_list = {"one","two"}
    my_obj = MyClass()
    my_obj.name = my_name;
    my_obj.my_list = my_list


    serialized_object = JSONserializer.serialize(my_obj).

Thank you.

A: 

How about the JSONEncoder class?

update

I must have skipped over the part about the data being contained in a class. If you want sane serialization of arbitrary Python objects without the need to extend the encoder, then maybe you can use a combination of pickle and json. When pickling, use protocol = 0 to serialize the data as human-readable ASCII.

Jeremy Brown
Still, i need to encode a class, and not only a simple type or an array. This class seems to require a manually defined serialization method in order to serialize a class. Maybe I'm wrong since I'm new with the language, but when I tested that's what I got.
Alexandre Deschamps
@Alexandre - updated my answer
Jeremy Brown
+2  A: 

How would you expect the json library to know how to serialize arbitrary classes?

In your case, if your class is simple enough, you might be able to get away something like

foo = FooObject() # or whatever
json_string = json.dumps(foo.__dict__)

to just serialize the object's members.

Deserialization would then need to be something like

foo_data = json.loads(json_string)
foo = FooObject(**foo_data)
Will McCutchen
Nah, it doesnt seems to work because my class has two members, which is a string and a list of strings
Alexandre Deschamps
It works for me: http://gist.github.com/574291. If your object really only has two members, a string and a list of strings, then the serialization will work. The deserialization technique I'm using relies on your object's `__init__` function to take arguments with the same names as the members. See the gist above for a working example.
Will McCutchen
+1  A: 

Don't know of anything pre-built, but you can write one if your objects are simple enough. Override the default method in the JSONEncoder to look at inspect.getmembers(obj) (inspect is a more readable way of getting at sets of attributes in __dict__).

#!/usr/bin/env python3

import inspect
from json import JSONEncoder


class TreeNode:

    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right


class ObjectJSONEncoder(JSONEncoder):

    def default(self, reject):
        is_not_method = lambda o: not inspect.isroutine(o)
        non_methods = inspect.getmembers(reject, is_not_method)
        return {attr: value for attr, value in non_methods
                if not attr.startswith('__')}


if __name__ == '__main__':
    tree = TreeNode(42,
        TreeNode(24),
        TreeNode(242),
    )
    print(ObjectJSONEncoder().encode(tree))

Update: @Alexandre Deschamps says isroutine works better than is method for some input.

cdleary
Thank you for the anwser, it almost does the trick except for two things. The is_not_method = lambda o: not inspect.ismethod(o) seems to also need the not inspect.isroutine(o) statement. It looks like in python a built-in method is a limit case. Also, my class needs a list to be serialized with. it looks like the elements in the list do not get serialized with it.
Alexandre Deschamps
@Alexandre Deschamps: I don't knwo what you mean... if you change those numbers in `__main__` to lists of numbers, it serializes just fine.
cdleary
Ok, I just found out I was the problem. I was using the {} instead of [] to make a list. As I said, I'm new to the language. It works fine. Just add the "not inspect.isroutine" to your example in case other people needs it. Thanks a lot for your time.
Alexandre Deschamps
@Alexandre Deschamps: Ah! That's not a list, that's a `set` datatype. It has no order, so there's not a straightforward mapping to JSON datatypes. If you stick an `if isinstance(reject, set): return list(reject)` in there, it'll work -- it'll just assign an arbitrary order to the values in the set in the resulting JSON array.
cdleary
It seems we saw it at the same time :P
Alexandre Deschamps