1

Is there a convention for JSON-serializing (and deserializing) Python objects to identify the object type? I've gone through this example solution below (which I find quite decent with slight modification), but I still wonder: is any safety concern and is it crystal-clear enough?

Result (Note the addition of the __type__ attribute)

{
  "__type__": "date",
  "year": 2022,
  "month": 1,
  "day": 1
}

is printed from the following code:

import json
from datetime import date, timedelta

class MyJSONEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, date):
            return {
                '__type__' : 'date',
                'year' : obj.year,
                'month' : obj.month,
                'day' : obj.day
            }   

        elif isinstance(obj, timedelta):
            return {
                '__type__' : 'timedelta',
                'days' : obj.days,
                'seconds' : obj.seconds,
                'microseconds' : obj.microseconds,
            }   
        # And more and more classes to support
        else:
            return super().default(self, obj)

class MyJSONDecoder(json.JSONDecoder):

    SUPPORTING_TYPES = {'date': date, 'timedelta': timedelta}

    def __init__(self):
            super().__init__(object_hook=self.dict_to_object)

    def dict_to_object(self, d): 

        if '__type__' in d and d['__type__'] in self.SUPPORTING_TYPES:
            obj_type = self.SUPPORTING_TYPES[d.pop('__type__')]
            return obj_type(**d)
        return d

# And to encode / decode

d = date(2022,1,1)
serialized_d = json.dumps(d, cls=MyJSONEncoder)
print(serialized_d)
d_ = json.loads(serialized_d, cls=MyJSONDecoder)

assert d == d_ # Assertion check
Aaron Lei
  • 96
  • 4
  • 1
    Your title and text suggest you're asking about serialisation of any type to .json, but the actual code seems to be specific to `datetime.date` and `datimetime.timedelta` - what is your question about? Are you asking whether for *any* type, writing this type of encoder/decoder is best practice? (Also, why exactly would you use json as the medium in this type of situation? Instead of, for example, pickle?) – Grismar Aug 05 '22 at 03:42
  • @Grismar Sorry I should be more specific of that is just an example. I'm asking about if using an additional key-value of '__type__' is a good practice for encode/decode of custom python object. I'll edit it correspondingly. – Aaron Lei Aug 05 '22 at 03:47
  • @Grismar I am not considering pickle is it is not human readable outside of python. – Aaron Lei Aug 05 '22 at 03:50

1 Answers1

1

Your methodology seems reasonable enough to me. However if I were working on a similar project I would try to simplify it as much as possible in order to simplify both ends of the serialization process.

For example, I wouldn't break down datetime objects into years months and days, Instead I would store it in either timestamp or isoformat depending on how readable I needed it to be. This would make converting to json as easy as date_time_obj.isoformat() and converting back to datetime would be datetime.fromisoformat().

The same goes for TimeDelta. Depending on how readable it needs to be I would just store the whole delta as seconds, which would reduce the number of items to parse and would reduce the serializing code to timedelta.total_seconds() and timedelta(seconds=arg). Very large deltas would be difficult to read though.

All that being said... your method is pretty simple as it is, so I would say the difference is completely subjective.

Alexander
  • 16,091
  • 5
  • 13
  • 29
  • Thanks for the suggestion. Very clear and practical, that can keep the json file at it simplest. My encoding idea is to match with the init parameters, so I don't need to extra thought process when decoding. – Aaron Lei Aug 05 '22 at 04:19
  • I googled `json datetime` and Google said *"JSON does not have a built-in type for date/time values. The general consensus is to store the date/time value as a string in ISO 8601 format."* (which it got from jsonata.org.) – Kelly Bundy Aug 05 '22 at 05:33
  • And [2000+ upvoted](https://stackoverflow.com/a/15952652/12671057). – Kelly Bundy Aug 05 '22 at 05:37
  • Yeah, just adding information/support, since you only said it's what *you* would do, not that that's a "convention" (what the question asks for) or the "concensus" (what Google/JSONata calls it). And maybe such googling and JSONata also lead to more information for other data types. – Kelly Bundy Aug 05 '22 at 05:42
  • @KellyBundy My focus is actually on Python object serialization (to json or yaml etc) for any generic custom class, while date and timedelta is just a concrete example. But still, thanks for the extra information! I also agree Alexander's answer is not an "answer", but still, a piece of good suggestion. – Aaron Lei Aug 05 '22 at 06:11