Learn to deserialize JSON string and convert deserialized JSON data to a custom class (e.g. User
) by extending JSONDecoder
or object_hook
method.
In Python custom deserialization example, we have following User
class. Here, birthdate
of type datetime and we can define any formatter string for it.
import datetime class User: def __init__(self, id, name, birthdate): self.id = id self.name = name if isinstance(birthdate, str): self.birthdate = datetime.datetime.strptime(birthdate, "%d %b %y") else: self.birthdate = birthdate
1. Python Custom Deserializer Method using object_hook
1.1. Add Deserializer Method to the Class
By default, json.load()
or json.loads()
methods read the JSON and return as python dictionary object. In the deserializer method, we have to convert the dict
to our custom class.
The given to_object()
method takes a dictionary method argument and creates a new User
instance by calling its constructor.
Notice how we are using the '__class__'
and '__module__'
attributes to validate that we are decoding the JSON to correct class in the correct module. The class and module information, in this case, is part of JSON data itself.
We are free to customize the deserialization logic as we need in the application.
class User: def __init__(self, id, name, birthdate): self.id = id self.name = name if isinstance(birthdate, str): self.birthdate = datetime.datetime.strptime(birthdate, "%d %b %y") else: self.birthdate = birthdate def to_object(d): if d['__class__'] == 'User' and d['__module__'] == 'user': inst = User(d['id'], d['name'], d['birthdate']) else: inst = d return inst
1.2. Use ‘object_hook’ attribute on json.loads()
Next, to use this deserializer method, use the object_hook attribute in json.loads()
method. It will be automatically called by python while converting JSON to the complex object.
import json from user import User # Python dict user_json = """{ "name": "Lokesh", "id": 39, "birthdate": "06 Jan 91", "__class__": "User", "__module__": "user" }""" # Use object_hook to execute custom deserialization code user_object = json.loads(user_json, object_hook=User.to_object) # Verify if we read the valid JSON and created the User object as desired print(user_object) print(json.dumps(user_object, default=User.to_dict))
Program output.
<user.User object at 0x000001A92F13AD90> {"id": 39, "name": "Lokesh", "birthdate": "06 Jan 91", "__class__": "User", "__module__": "user"}
2. Python Custom Deserialization using JSONDecoder
Another way, to add custom deserialization logic, is to extend the JSONDecoder
class.
The following ComplexDecoder
class declares the dict_to_object()
method which provides the logic to convert the JSON to the complex class.
The dict_to_object()
method checks all dictionary objects read by json.loads()
method and checks the '__class__'
and '__module__'
properties in dictionary.
If it finds the class and module information, dict_to_object()
method imports and loads the class. It then creates a new instance of the class by calling its constructor and passing dictionary key-value pairs as constructor arguments.
import json class ComplexDecoder(json.JSONDecoder): def __init__(self): json.JSONDecoder.__init__( self, object_hook=self.dict_to_object, ) def dict_to_object(self, d): if '__class__' in d: class_name = d.pop('__class__') module_name = d.pop('__module__') module = __import__(module_name) class_ = getattr(module, class_name) args = { key: value for key, value in d.items() } inst = class_(**args) else: inst = d return inst
1.2. Use ‘cls’ attribute on json.dumps()
To use custom JSONDecoder
, use the cls attribute in json.loads()
method. It will be automatically called by python while converting the JSON to the complex object.
import json from complex_decoder import ComplexDecoder from user import User # Python dict user_json = """{ "name": "Lokesh", "id": 39, "birthdate": "06 Jan 91", "__class__": "User", "__module__": "user" }""" # Use ComplexDecoder to execute custom deserialization code user_object = json.loads(user_json, cls=ComplexDecoder) print(user_object) print(json.dumps(user_object, default=User.to_dict))
Program output.
<user.User object at 0x0000019533E96880> {"id": 39, "name": "Lokesh", "birthdate": "06 Jan 91", "__class__": "User", "__module__": "user"}
Happy Learning !!
Leave a Reply