5

Generally, we can define __str__ method to make str(obj) return what we want.

But now I want to define my Model object to return a default JSON string when using json.dumps(obj).

Is there any nice way for me to declare a method in the class to do this?

class MyClass:
    ...
    def __json__(self):
        return {'name': self.name, 'age': self.age}

obj = MyClass()

json.dumps(obj) # returns the same as json.dumps(obj.__json__)
4
  • 1
    You can use a custom JSONEncoder Commented Jun 4, 2014 at 6:14
  • What needs to happen when the string gets loads'd? Commented Jun 4, 2014 at 6:18
  • I don't concern about that, loads returns dict is ok. @user2357112 Commented Jun 4, 2014 at 6:19
  • The python json module docs includes short examples for extending to custom classes. Their example is complex numbers. Could you try adapting that? Commented Jun 4, 2014 at 6:22

2 Answers 2

9

If you only need Python -> JSON, it's simple to write a JSONEncoder class that calls such a method for any object:

class AutoJSONEncoder(JSONEncoder):
    def default(self, obj):
        try:
            return obj._json()
        except AttributeError:
            return JSONEncoder.default(self, obj)

You can then use the class directly AutoJSONEncoder().encode(obj) or through the dumps interface json.dumps(obj, cls=AutoJSONEncoder).

The reverse direction requires at least a list of classes for which to call a _fromjson method.

(Note: __foo__ names are reserved so you shouldn't define them for your own purposes. __bar invokes name mangling, which probably isn't what you want.)

Sign up to request clarification or add additional context in comments.

6 Comments

Well, this is I want. But I tried the code, it seems not works by default, how can it be?
You need to make sure you are using the custom class instead of the default JSONEncoder. You can pass the class name to json.dumps using the cls parameter. If you already have a bunch of dumps calls and don't want to add it to all of them, you can define your own using dumps = lambda obj: json.dumps(obj, cls=AutoJSONEncoder).
OK, thanks alot! I edited your answer to add the call method.
For more, when I tried AutoJSONEncoder().encode([obj1, obj2]), I got an error, can this be possible?
It raises [<...>] is not JSON serializable, Exception Type: TypeError, I just want it automatically cascading, is that possible? @otus
|
9
import json


class MyEncoder(json.JSONEncoder):
    """
    JSONEncoder subclass that leverages an object's `__json__()` method,
    if available, to obtain its default JSON representation. 

    """
    def default(self, obj):
        if hasattr(obj, '__json__'):
            return obj.__json__()
        return json.JSONEncoder.default(self, obj)


class MyClass(object):
    name = 'John'
    age = 30

    def __json__(self):
        return {'name': self.name, 'age': self.age}

>>> json.dumps(MyClass(), cls=MyEncoder)
{"age": 30, "name": "John"}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.