AmericanMade AmericanMade - 1 year ago 76
JSON Question

__dict__ Doesn't Allow Call to Method in Python

I am creating a dictionary of objects that I'd like to save and re-load at a different time (I want to do this with the "json" module, not "pickle").

I have one class created (let's call it "Ball"), and the dictionary just contains many different instances of that class. The way it looks is:

my_dict = {
"ball1": {"size": "big", "baseball": False, etc...},
"ball2": {"size": "small", "baseball": True, etc...},

As I create new instances of the "Ball" class, I just APPEND them to "my_dict".

My "Ball" class has methods that allow me to change the value of certain

changeSize(self, size)


In order for me to get the save ability to work properly with the json module I have had to do the following to each new instance of the "Ball" class:

newBall = Ball(name)
my_dict[name] = newBall.__dict__

Adding the


and then appending that to the dictionary makes it JSON serializable, BUT it makes it so that when I go in to "Edit Mode" I can't call the method (ie changeSize(name) ) because it is just a dictionary and no longer a "Ball" object.

How do I make it so that I can save (using json module) and also use the methods that I have in place to edit?

Also, the way I am saving/loading is as follows:

out_file = open("testSave.json"), "w")
json.dump(my_dict, out_file, indent=4)

in_file = open("testSave.json", "r")
my_dict = json.load(in_file)


Answer Source

Ultimately, json doesn't support serializing arbitrary python objects. If you want to do that, you can have a look at pickle.

Alternatively, you can create an alternate constructor on your Ball that will initialize it with values from the dict:

class Ball(object):

    def from_json(self, dictionary):
        b = cls()
        return b


I've written this assuming that the Ball constructor can be called with 0 arguments -- you may need to modify the code if that isn't the case, or if __init__ does anything "fancy" (beyond setting json serializable attributes). One way around the requirement of the arguments of __init__ is to use __new__ to create the instance and then just populate the members by updating the class dictionary:

class Ball(object):
    def __init__(self, name, foo, bar): = name = foo = bar

    def to_dict(self):
        return self.__dict__

    def from_dict(cls, dictionary):
        self = cls.__new__(cls)
        return self

    def __str__(self):
        return 'Ball(%r, %r, %r)' % (,,

b = Ball('HockyPuck', 'flat', 'NotABall')
d = b.to_dict()
bb = Ball.from_dict(d)


This works in both python2.x and 3.x.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download