0

I have a a python object that is a defaultdict that uses a class object as its default value. This class object contains various variables, some of which are Decimal data types, one is a date time data type, and a couple variables are lists that in turn contain objects that have variables as Decimal data types, date time variables, as well as lists that can in turn have further nested objects.

class ReportObject(object):
    def __init__(self):
        self.name = None
        self.amount1 = Decimal(0.00)
        self.amount2 = Decimal(0.00)
        self.amount1_transactions = [] # This list can contain nested objects that inherit from the ReportObject
        self.amount2_transactions = [] # This list can contain nested objects that inherit from the ReportObject
        self.purchaseOrder = {}

    def __str__(self):
        return self.__dict__

    def __repr__(self):
        return str(self.__dict__)

    def __json__(self):
        dt = {}
        for key, value in self.__dict__.items():
            if type(value) == 'list':
                dt_list = list()
                for dt_val in value:
                    dt_list.append(dt_val.__json__())
                dt[key] = dt_list
            else:
                dt[key] = str(value)
        return dt

The data that I'm trying to json.dumps is a defaultdict of these ReportObjects.

When I go to call json.dumps(data, default: lambda o: o.__json__()) the variables that are a list are getting represented as raw strings instead of being an array of the objects in each list. Is there a cleaner way to code this custom JSON Encoding functionality? I couldn't figure out how to implement a solution from subclassing json.JSONEncoder.

martineau
  • 119,623
  • 25
  • 170
  • 301
Jasonca1
  • 4,848
  • 6
  • 25
  • 42

1 Answers1

1

if type(value) == 'list': will never evaluate to true, so you were always executing the else case (which stringified the value, as you observed); type(value) returns the class that value is an instance of, not a string describing it. The test you want is:

if type(value) is list:      # Only allows lists; since types are singletons, use identity test, not equality

or:

if isinstance(value, list):  # Allows list subclasses

Note the lack of quotes around list; that refers to the type, not a string describing it.

martineau
  • 119,623
  • 25
  • 170
  • 301
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Would there be a more pythonic way to solve this by subclassing json.JSONEncoder? – Jasonca1 Jan 03 '19 at 01:30
  • 2
    @Jasonca1: It could also be done that way. See the question [Making object JSON serializable with regular encoder](https://stackoverflow.com/questions/18478287/making-object-json-serializable-with-regular-encoder) for an example of doing that (in my answer). – martineau Jan 03 '19 at 01:36
  • @martineau Is their a way to keep all the json encoding logic in the subclassed JSONEncoder rather than having to both define a special method on the object and subclassing the JSONEncoder to invoke that method when calling dumps? – Jasonca1 Jan 03 '19 at 01:38
  • @Jasonca1: Yes, there is. Please read _all_ of my answer to the question. – martineau Jan 03 '19 at 01:42