Class method to write JSON to file

Viewed 105

I'm struggling with the following class method:

class Base:
    def to_json_string(list_dictionaries):
        if list_dictionaries is None or len(list_dictionaries) == 0:
            return "[]"
        return json.dumps(list_dictionaries)

    @classmethod
    def save_to_file(cls, list_objs):
        filename = cls.__name__ + ".json"
        with open(filename, "w") as f:
            f.write(cls(Base.to_json_string(list_objs)))

I have a class Rectangle that inherits from Base. To which I can pass in the class method save_to_file and it will create me a file named Rectangle.json with a list of objects JSON formatted.

Example:

r1 = Rectangle(10, 7, 2, 8)
r2 = Rectangle(2, 4)
Rectangle.save_to_file([r1, r2])

with open("Rectangle.json", "r") as file:
    print(file.read())

Output:

[{"y": 8, "x": 2, "id": 1, "width": 10, "height": 7}, {"y": 0, "x": 0, "id": 2, "width": 2, "height": 4}]

But it's raising a TypeError message "TypeError: Object of type Rectangle is not JSON serializable"

I'm new to OOP in Python and still don't figure out how to use cls properly. So my error lays here:

@classmethod
def save_to_file(cls, list_objs):
    filename = cls.__name__ + ".json"
    with open(filename, "w") as f:
        f.write(cls(Base.to_json_string(list_objs)))
1 Answers

Your error is with the assumption that the json module automatically knows how to transform your custom object into JSON. You just need to fix your to_json_string, that's all. This could work:

def to_json_string(list_dictionaries):
    if not list_dictionaries:
        return "[]"
    return json.dumps([element.__dict__ for element in list_dictionaries])

However, using __dict__ is pretty brittle, it's better to define specifically inside the Rectangle class what attributes should be part of the dict/how it should be serialized.

It's also not considered good style to just attach plain functions to classes, if it has nothing to do with Base functionality (which it doesn't, if it isn't a class or instance method), I would just keep it outside the class. Or at least use a @staticmethod decorator so noone accidentally calls some_object.to_json_string() (which wouldn't work).

Related