george lal
george lal

Reputation: 57

object not json serializable

While coding in python I'm getting an error: "Object of type myObject is not JSON serializable"

I tried to use some solutions I saw in other questions, but I didn't find many similarities between my code and the code in those questions, so I found it difficult to adapt the solutions in my code.

A part of my script is as follows. The error occurs in the last line of the first block:

import json
import os
from my_object import myObject

for a in A_set:
    if os.path.isfile(filename):
        with open(filename, 'r') as f:
            json_data = json.load(f)
        object_name = myObject.from_json(json_data)
    else:
        object_name = myObject(a)
        object_name.property_A = property_A
        object_name.property_C = []

    object_name.property_C_add_elements(var)
    with open(filename, 'w') as f:
        json.dump(object_name.to_json(), f)

In another python file is defined the class of 'myObject', where is also the method 'to_json()', which I'm calling in the line of code that produces the error.

class myObject:
    def __init__(self, name):
        self.name = name
        self.property_A = property_A
        self.property_B = property_B
        self.property_C = []

    def property_C_add_elements(self, var):  
        self.property_C.append(var)

    def to_json(self):
        return {
            'Name': self.name,
            'property A': self.property_A,
            'property B': self.property_B,
            'property C': self.property_C
        }

    @classmethod
    def from_json(cls, jason_data):
        object_name = myObject(jason_data['property A'])
        property_B = myObject(jason_data['property B'])
        c_list = []
        for var in jason_data['property C']:
            c_list.append(myObject(var))

        object_name.property_B = property_B
        object_name.property_C = c_list

        return object_name

I would be glad if I could get a solution to that problem. Thanks in advance.

Upvotes: 0

Views: 5214

Answers (2)

Chgad
Chgad

Reputation: 882

from the code you provided i can only speculate what types exactly your property_A, property_B, property_C variables/attributes are but

@classmethod
def from_json(cls, jason_data):
    object_name = myObject(jason_data['property A'])
    property_B = myObject(jason_data['property B'])
    c_list = []
    for var in jason_data['property C']:
        c_list.append(myObject(var))

    object_name.property_B = property_B
    object_name.property_C = c_list

    return object_name

Let's me speculate that your properties are Classinstances which have no "definition" of how they should be serialized into JSON. This is backed up by what you said :

"Object of type myObject is not JSON serializable"

I guess the problem is with the from_json() classmethod, there you should probably do smth. like :

EDITED:

Assuming that the __init__() method of your Class looks as follows

def __init__(self, name, property_A, property_B, property_C):
    self.name = name
    self.property_A = property_A
    self.property_B = property_B
    self.property_C = property_C 
    # property_C should be a list, you may want to add validation method 
    # which checks for correct types if it is preocess cirtical

I suggest the following:

@classmethod
def from_json(cls, jason_data):
    return cls(
               jason_data['name'],
               jason_data['property A'],
               jason_data['property B'],
               jason_data['property C']
               ) 

Furthermore i suggest, if it's possible, that you change your JSON Format, provided in your to_json() method by simply replacing the whitespaces from "property A" to "property_A" (same for other properties). In addition you can change "Name" to lowercase "name".

Why ? Because with this format, and my changed __init__() method you can convert your from_json() to the following utilizing unpacking operation :

@classmethod
def from_json(cls, jason_data):
    return cls(**json_data) 

Upvotes: 0

CristiFati
CristiFati

Reputation: 41116

Here's a modified (and working) version of your code.

custom_object.py:

class CustomObject:

    @classmethod
    def from_json(cls, json_data):
        name = json_data["Name"]
        prop_a = json_data["PropertyA"]
        prop_b = json_data["PropertyB"]
        obj = cls(name, prop_a=prop_a, prop_b=prop_b)
        for var in json_data["PropertyC"]:
            obj.add_c_element(var)
        return obj

    def __init__(self, name, prop_a="", prop_b=""):
        self.name = name
        self.prop_a = prop_a
        self.prop_b = prop_a
        self.prop_c = list()

    def add_c_element(self, var):
        self.prop_c.append(var)

    def to_json(self):
        return {
            "Name": self.name,
            "PropertyA": self.prop_a,
            "PropertyB": self.prop_b,
            "PropertyC": self.prop_c,
        }

code.py:

#!/usr/bin/env python3

import sys
import json
import os
from custom_object import CustomObject


def main():
    filename = "./data.json"
    if os.path.isfile(filename):
        print("Attempting to load object from json file...")
        with open(filename, "r") as f:
            json_data = json.load(f)
            try:
                obj = CustomObject.from_json(json_data)
            except Exception as e:
                print(e)
                return
            print("Object: {:}\n  Class: {:s}\n  Attributes:" .format(obj, obj.__class__.__name__))
            for k, v in getattr(obj, "__dict__", dict()).items():
                print("    {:s}: {:}".format(k, v))

    else:
        print("Creating dummy object and saving to json...")
        obj = CustomObject("Object name", prop_a="object property a", prop_b="object property b")
        obj.add_c_element(1)
        obj.add_c_element("c element 2")
        with open(filename, "w") as f:
            json.dump(obj.to_json(), f)
    print("Done.")


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Notes:

  • Corrected the errors (or added data that was missing)
  • Did some renames (class, objects, attributes) for clarity
  • Assumed that prop_a, prop_b are strings (not very important)
  • The (main) problem was in from_json function (I'm not sure what you tried to do there: why so many myObject instantiations, when there should have been only one). Anyway, what it does now:
    1. Gets name, prop_a, prop_b attributes from json_data (which is a dict)
    2. Constructs the object out of the 3 values from #1.
    3. Read the objects for prop_c, and adds them one by one (if any) to the object (by calling add_c_element)
  • Program searches for a file (with json contents):
    • If found, it tries to load the object from it and displays it
    • If not found, it creates a dummy object and dumps it in the file
  • This is one (not a very nice) way of doing things. It's meant to require minimum code changes, and it's also for learning purposes. The proper (scalable, general) way would be to extend JSONEncoder, JSONDecoder ([Python 3]: json - JSON encoder and decoder), but I feel that it would be a bit too advanced at this point

Output:

(py35x64_test) e:\Work\Dev\StackOverflow\q053914912>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32

Creating dummy object and saving to json...
Done.

(py35x64_test) e:\Work\Dev\StackOverflow\q053914912>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32

Attempting to load object from json file...
Object: <custom_object.CustomObject object at 0x00000230B6182C88>
  Class: CustomObject
  Attributes:
    prop_a: object property a
    prop_b: object property a
    name: Object name
    prop_c: [1, 'c element 2']
Done.

Upvotes: 1

Related Questions