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?