I’m building some Python code to read and manipulate deeply nested dicts (ultimately for interacting with JSON services, however it would be great to have for other purposes) I’m looking for a way to easily read/set/update values deep within the dict, without needing a lot of code.
@see also Python: Recursively access dict via attributes as well as index access? — Curt Hagenlocher’s “DotDictify” solution is pretty eloquent. I also like what Ben Alman presents for JavaScript in http://benalman.com/projects/jquery-getobject-plugin/ It would be great to somehow combine the two.
Building off of Curt Hagenlocher and Ben Alman’s examples, it would be great in Python to have a capability like:
>>> my_obj = DotDictify()
>>> my_obj.a.b.c = {'d':1, 'e':2}
>>> print my_obj
{'a': {'b': {'c': {'d': 1, 'e': 2}}}}
>>> print my_obj.a.b.c.d
1
>>> print my_obj.a.b.c.x
None
>>> print my_obj.a.b.c.d.x
None
>>> print my_obj.a.b.c.d.x.y.z
None
Any idea if this is possible, and if so, how to go about modifying the DotDictify solution?
Alternatively, the get method could be made to accept a dot notation (and a complementary set method added) however the object notation sure is cleaner.
>>> my_obj = DotDictify()
>>> my_obj.set('a.b.c', {'d':1, 'e':2})
>>> print my_obj
{'a': {'b': {'c': {'d': 1, 'e': 2}}}}
>>> print my_obj.get('a.b.c.d')
1
>>> print my_obj.get('a.b.c.x')
None
>>> print my_obj.get('a.b.c.d.x')
None
>>> print my_obj.get('a.b.c.d.x.y.z')
None
This type of interaction would be great to have for dealing with deeply nested dicts. Does anybody know another strategy (or sample code snippet/library) to try?
Attribute Tree
The problem with your first specification is that Python can’t tell in
__getitem__if, atmy_obj.a.b.c.d, you will next proceed farther down a nonexistent tree, in which case it needs to return an object with a__getitem__method so you won’t get anAttributeErrorthrown at you, or if you want a value, in which case it needs to returnNone.I would argue that in every case you have above, you should expect it to throw a
KeyErrorinstead of returningNone. The reason being that you can’t tell ifNonemeans “no key” or “someone actually storedNoneat that location”. For this behavior, all you have to do is takedotdictify, removemarker, and replace__getitem__with:Because what you really want is a
dictwith__getattr__and__setattr__.There may be a way to remove
__getitem__entirely and say something like__getattr__ = dict.__getitem__, but I think this may be over-optimization, and will be a problem if you later decide you want__getitem__to create the tree as it goes likedotdictifyoriginally does, in which case you would change it to:I don’t like the
markerbusiness in the originaldotdictify.Path Support
The second specification (override
get()andset()) is that a normaldicthas aget()that operates differently from what you describe and doesn’t even have aset(though it has asetdefault()which is an inverse operation toget()). People expectgetto take two parameters, the second being a default if the key isn’t found.If you want to extend
__getitem__and__setitem__to handle dotted-key notation, you’ll need to modifydoctictifyto:Test code: