Today, I was building a REST client for one of the REST server applications using Python. I decided to use Python requests library for writing my REST API client. Requests is a very easy to use library that you can use to quickly bootstrap your REST API client. Writing REST client for REST endpoints was a matter of an hour. This REST API client will be used from our custom Jython(JVM implementation of Python) REPL. REST API has only two endpoints that return JSON objects. Response of first endpoint was fed to the second endpoint. I was returning the JSON response as Python dictionary. User can change values of the first response and pass it to the second API call. In Python, you work with dictionary as shown below.
my_dict = {"one": 1, "two": 2, "three": 3} my_dict["one"] # return 1
We wanted to make sure users of our Jython REPL can access dictionary like object property access as shown below.
mydict.one # Should return 1
You can make Python dict support object access by writing your own dictionary extend dict
. Then, you have to provide implementation of __getattr__
and __setattr__
methods as shown below.
class DictWithAttributeAccess(dict): def __getattr__(self, key): return self[key] def __setattr__(self, key, value): self[key] = value
In the code show above:
1. We created a new class DictWithAttributeAccess
that extends dict
.
2. __getattr__
is called when an attribute lookup has not found the attribute in the usual place. So, if attribute is not found, just look up in the dictionary.
3. __setattr__
is called when an attribute assignment is attempted. This method will be used for assignment instead of default mechanism.
If your method return DictWithAttributeAccess
instead of Python dict
then you can access like object.
my_dict = {"one": 1, "two": 2, "three": 3} another_dict = DictWithAttributeAccess(my_dict) another_dict.one # return 1
This works if you don’t have nested dictionary structure. I was using Python json
module convert response into dictionary.
json.loads(response.text)
The above method converts JSON into Python dictionary. json
module converts all JSON objects into dictionary. So, if we convert the top level dictionary into DictWithAttributeAccess
we can’t access nested dictionaries with object access.
def parse_response(self, response): return DictWithAttributeAccess(json.loads(response.text))
What we wanted was to use DictWithAttributeAccess
for all dictionaries even when they are nested. This can be solved by object_hook
parameter of json.loads
method as shown below.
def parse_response(self, response): return json.loads(response.text, object_hook = lambda dict: DictWithAttributeAccess(dict))
According to documentation,
object_hook
is an optional function that will be called with the result of any object literal decoded (a dict). The return value ofobject_hook
will be used instead of thedict
.
Thanks for this GREAT post, Shekhar. SO helpful to my understanding of object_hook’s.