I have a base class:
#!/usr/bin/python3
"""Base class for all other classes in this module"""
import json
class Base:
"""Base Class
Args:
__nb_objects (int): number of instances of class
"""
__nb_objects = 0
def __init__(self, id=None):
"""class constructor
Args:
id (int, optional): argument value to initialize. Defaults to None.
"""
if id is not None:
self.id = id
else:
type(self).__nb_objects = 1
self.id = type(self).__nb_objects
@staticmethod
def to_json_string(list_dictionaries):
"""returns the JSON string representation of list_dictionaries
Args:
list_dictionaries ([{}]): a list of 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):
"""writes the JSON string representation of list_objs to a file
Args:
list_objs (list): list of instances who inherits of Base
"""
filename = type(list_objs[0]).__name__ ".json"
json_file = open(filename, "w")
if list_objs is None:
json.dump([], json_file)
if type(list_objs[0]).__name__ == "Rectangle":
new_dict = [item.to_dictionary() for item in list_objs]
json_string = cls.to_json_string(new_dict)
json.dump(new_dict, json_file)
json_file.close()
and a Child class:
#!/usr/bin/python3
"""Definition of Rectangle"""
from . base import Base
class Rectangle(Base):
"""define a rectangle object
Args:
Base (class): Base Class
"""
def __init__(self, width, height, x=0, y=0, id=None):
"""rectangle constructor
Args:
width (int): width of rectangle
height (int): height of rectangle
x (int, optional): x offset of rectangle. Defaults to 0.
y (int, optional): y offset of rectangle. Defaults to 0.
id (int, optional): identifier. Defaults to None.
"""
super().__init__(id)
if type(width) is not int:
raise TypeError('width must be an integer')
if width < 1:
raise ValueError('width must be > 0')
self.width = width
if type(height) is not int:
raise TypeError('height must be an integer')
if height < 1:
raise ValueError('height must be > 0')
self.height = height
if type(x) is not int:
raise TypeError('x must be an integer')
if x < 0:
raise ValueError('x must be >= 0')
self.x = x
if type(y) is not int:
raise TypeError('y must be an integer')
if y < 0:
raise ValueError('y must be >= 0')
self.y = y
@property
def width(self):
"""Getter and Setter methods for width"""
return self.width
@width.setter
def width(self, value):
if type(value) is not int:
raise TypeError('width must be an integer')
if value < 1:
raise ValueError('width must be > 0')
self.width = value
@property
def height(self):
"""Getter and Setter methods for height"""
return self.height
@height.setter
def height(self, value):
if type(value) is not int:
raise TypeError('height must be an integer')
if value < 1:
raise ValueError('height must be > 0')
self.height = value
@property
def x(self):
"""Getter and Setter methods for x"""
return self.x
@x.setter
def x(self, value):
if type(value) is not int:
raise TypeError('x must be an integer')
if value < 0:
raise ValueError('x must be >= 0')
self.x = value
@property
def y(self):
"""Getter and Setter methods for y"""
return self.y
@y.setter
def y(self, value):
if type(value) is not int:
raise TypeError('y must be an integer')
if value < 0:
raise ValueError('y must be >= 0')
self.y = value
def area(self):
"""returns the area value of the Rectangle instance"""
return self.width * self.height
def display(self):
"""prints in stdout the Rectangle instance with the character #"""
print(('\n' * self.y) '\n'
.join(' ' * self.x '#' * self.width
for _ in range(self.height)))
def __str__(self):
"""Returns an informal string representation a Rectangle object"""
return '[Rectangle] ({}) {}/{} - {}/{}'\
.format(self.id, self.x, self.y,
self.width, self.height)
def update(self, *args, **kwargs):
"""update the instance attributes"""
if len(kwargs):
if 'height' in kwargs:
self.height = kwargs['height']
if 'width' in kwargs:
self.width = kwargs['width']
if 'x' in kwargs:
self.x = kwargs['x']
if 'y' in kwargs:
self.y = kwargs['y']
if 'id' in kwargs:
self.id = kwargs['id']
else:
try:
self.id = args[0]
self.width = args[1]
self.height = args[2]
self.x = args[3]
self.y = args[4]
except IndexError:
pass
def to_dictionary(self):
"""returns the dictionary representation of a Rectangle"""
return self.__dict__
and here is the main file:
#!/usr/bin/python3
""" 15-main """
from models.rectangle import Rectangle
if __name__ == "__main__":
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())
The task is to use the "to_json_string" method (which returns a json string of a list of dictionaries of instance attributes) in Base to write the function "save_to_file" that saves a list of dictionaries of instance attributes that inherits from base
to_json_string accepts a list of dictionaries and save_to_file accepts a list of instances of the child class Recangle(list_objs), so in order to pass list_objs to to_json_string, I have to create a list of dictionaries of instance attributes, which is what this line does:
new_dict = [item.to_dictionary() for item in list_objs]
but when I pass this list to to_json_string and try to dump it in the file Rectangle.json, with the lines
new_dict = [item.to_dictionary() for item in list_objs]
json_string = cls.to_json_string(new_dict)
json.dump(json_string, json_file)
I get an output like:
"[{\"id\": 1, \"width\": 10, \"height\": 7, \"x\": 2, \"y\": 8}, {\"id\": 2, \"width\": 2, \"height\": 4, \"x\": 0, \"y\": 0}]"
But when dump list to the file, I get the list of dictionaries in the file like:
[{"id": 1, "width": 10, "height": 7, "x": 2, "y": 8}, {"id": 2, "width": 2, "height": 4, "x": 0, "y": 0}]
So why do I get the output with the double quotes and how can I use the to_json_string to get the correct output?
CodePudding user response:
The issue is that you try to json dump twice, once in to_json_string
and then again with the result, so you get a string, and then write that string as the entire content (the resulting string is valid json, however dubiously)
>>> d = {"foo": "bar"}
>>> print(json.dumps(json.dumps(d)))
"{\"foo\": \"bar\"}"
>>> print(json.dumps(d))
{"foo": "bar"}
You could remove one .dump
instance, make the dump stringifying optional, set some flag, check for a string before re-.dump
-ing, or whatever other logic you like instead!