A note on how to encode an object of a class defined by yourself in Python and how to decode it from Json format. Referenced page:
Take this class as an example.
import json
from datetime import date
class MyA:
def __init__(self, i=0, d=date.today()):
self.i = i #int type
self.d = d #date type
First of all, we have to think about the format of the object as Json data. It seems natural for the MyA object to be an object with 'i'
and'd'
as keys. Also, date type data may be a character string, but let's quickly convert it to an integer with the toordinal method. Then, for example
a = MyA(i=100, d=date(year=2345, month=6, day=12))
The a defined as is converted to the Json data {"i ": 100," d ": 856291}
. This may be fine, but it can be tedious because you don't know what type to revert to when decoding. Therefore, the class name is stored in the key '_type'
, and the value is stored in the key 'value'
. As a result, the Json data looks like this:
{ "_type": "MyA",
"value": {"i": 100,
"d": { "_type": "date",
"value": 856291}}}
The dump and dumps commands in Python's json library take an argument called cls. You can specify your own encoder here. Since JSONEncoder is a commonly used class, I make my own encoder based on this. What you really need to do is redefine a method called default.
class MyEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, date):
return {'_type': 'date', 'value': o.toordinal()}
if isinstance(o, MyA):
return {'_type': 'MyA', 'value': o.__dict__}
return json.JSONEncoder.default(self, o)
As you can see, you only have to write what each class is looking at directly, and the library will do the recursion for you. (In the case of MyA class object, what is returned is a dictionary, and date type data may be set there.)
It can be executed as follows.
a = MyA(100, date(year=2345, month=6, day=12))
js = json.dumps(a, cls=MyEncoder)
print(js)
Execution result:
{"_type": "MyA", "value": {"i": 100, "d": {"_type": "date", "value": 856291}}}
This also creates a decoder based on a class called JSONDecoder. This time, when the object of the parent class JSONDecoder is created, write it so that the necessary decoding is performed in the function passed to the variable called object_hook. It looks like this:
class MyDecoder(json.JSONDecoder):
def __init__(self, *args, **kwargs):
json.JSONDecoder.__init__(self, object_hook=self.object_hook,
*args, **kwargs)
def object_hook(self, o):
if '_type' not in o:
return o
type = o['_type']
if type == 'date':
return date.fromordinal(o['value'])
elif type == 'MyA':
return MyA(**o['value'])
As o of object_hook, the result of normal decoding is passed. In the above example, a dictionary with '_type'
and 'value'
as keys will come, so you can write the code to recreate it as an object of the appropriate class. Again, you don't have to think about recursive processing.
Following the execution at the time of encoding:
b = json.loads(js, cls=MyDecoder)
print(b.i, b.d)
Execution result:
100 2345-06-12
Recommended Posts