简体   繁体   中英

What is the best practice to pass a class to json?

Problem: I have an instance of a class and I want to pass the main infos of the class to a json compatible format. I often resort to create a to_dict method like this:

class A:
    def __init__(self, name, val):
        self.name = name
        self.val = val

    def to_dict(self):
        return {
            'name': self.name,
            'val': self.val,
        }

Then i can do

a = A("a_name", 5)
a.to_dict()

which outputs {'name': 'a_name', 'val': 5}

However I think it is a bit inelegant. I considered modifying the __repr__ but I don't think it is better as I sometimes want a repr that is not a dict.

So my question: is there a better way to do this in python?

The Python standard library json module's documentation says:

To extend this to recognize other objects, subclass and implement a default() method with another method that returns a serializable object for o if possible, otherwise it should call the superclass implementation (to raise TypeError ).

So you could do something like

from json import JSONEncoder

class MyJSONEncoder(JSONEncoder):
    def default(self, o):
        if isinstance(o, A):
            return f'{{"name": "{o.name}", "value": {o.value}}}'
        return super().default(o)

# ... 

print(json.dumps(something, cls=MyJSONEncoder))

What I ended up doing to slightly generalize this was to say

    def default(self, o):
        if hasattr(o, '__json__'):
            return o.__json__()
        return super().default(o)

and then define a __json__ method in the classes I wanted to specify a JSON serialization format for.

There are several alternatives. For instance, you could make the instances iterable, and let that yield key/value pairs. Then use the dictionary constructor to take those key/value pairs:

class A:
    def __init__(self, name, val):
        self.name = name
        self.val = val

    def __iter__(self):
        yield "name", self.name
        yield "val", self.val

a = A("Helen", 42)
d = dict(a)

You can also use __dict__ ,

from the example above:

class A:
    def __init__(self, name, val):
        self.name = name
        self.val = val

a = A("Helen", 42)
print(a.__dict__)

# >>> {'name': 'Helen', 'val': 42}

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