Addressing Nested Dictionaries in Python
I think that post title is right. Essentially I mean dynamically accessing attributes from nested dictionaries or tuples.
Let's say you've got a JSON response like this:
{
"error": false,
"body": {
"name": "John",
"job": {
"company": "What Cheer",
"position": "Developer"
}
}
}
The JSON module would convert that into nested dictionaries, like this:
>>> print usr
{u'body': {u'job': {u'position': u'Developer', u'company': u'What Cheer'}, u'name': u'John'}, u'error': False}
In my case, I was trying to provide a runtime specified format string which could use any of the values at any depth.
There isn't (to my knowledge) an easy way to address into a deep structure with a single string. I considered value based format strings ('%(name)s' but there is no way to descend from there either.
My solution was to use a dot notation and evaluate it for field values.
This requires a strict policy not to use dots in your keys, but that is not an issue for my use case.
Here is my code for the dot notation:
def getByDotNotation( obj, ref ):
val = obj
for key in ref.split( '.' ):
val = val[key]
return val
And here it is in use against the object above:
>>> getByDotNotation( usr, 'body.name' )
u'John'
>>> getByDotNotation( usr, 'body.job.position' )
u'Developer'
>>> getByDotNotation( usr, 'error' )
False
>>>
The next (optional) step would be to create a wrapper object.
class DotAccessibleDict ( object ):
def __init__ ( self, data ):
self._data = data
def __getitem__ ( self, name ):
val = self._data
for key in name.split( '.' ):
val = val[key]
return val
Which we can then use like so:
>>> wrapped = DotAccessibleDict( usr )
>>> wrapped['body.name']
u'John'
>>> wrapped['body.job.position']
u'Developer'
>>> wrapped['error']
False
>>> wrapped['nope']
Traceback (most recent call last):
File "", line 1, in
File "", line 7, in __getitem__
KeyError: 'nope'
>>>
While this is just sugar, it does look nice doesn't it? To be complete you would want to implement the other sequence methods such as __setitem__
So that's my fix - what's yours?