Skip to content

Instantly share code, notes, and snippets.

@einnocent
Last active July 24, 2017 20:05
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save einnocent/8854896 to your computer and use it in GitHub Desktop.
Save einnocent/8854896 to your computer and use it in GitHub Desktop.
Modified Python Dotdictify
# turn dict into an object that allows access to nested keys via dot notation
# from http://stackoverflow.com/questions/3797957/python-easily-access-deeply-nested-dict-get-and-set
# made three modifications:
# --added `get()` method
# --added `if not dict.__contains__...` to `__contains__()`
# --can now accept None as key
class dotdictify(dict):
def __init__(self, value=None):
if value is None:
pass
elif isinstance(value, dict):
for key in value:
print key
self.__setitem__(key, value[key])
else:
raise TypeError, 'expected dict'
def __setitem__(self, key, value):
if key is not None and '.' in key:
myKey, restOfKey = key.split('.', 1)
target = self.setdefault(myKey, dotdictify())
if not isinstance(target, dotdictify):
raise KeyError, 'cannot set "%s" in "%s" (%s)' % (restOfKey, myKey, repr(target))
target[restOfKey] = value
else:
if isinstance(value, dict) and not isinstance(value, dotdictify):
value = dotdictify(value)
dict.__setitem__(self, key, value)
def __getitem__(self, key):
if key is None or '.' not in key:
return dict.__getitem__(self, key)
myKey, restOfKey = key.split('.', 1)
target = dict.__getitem__(self, myKey)
if not isinstance(target, dotdictify):
raise KeyError, 'cannot get "%s" in "%s" (%s)' % (restOfKey, myKey, repr(target))
return target[restOfKey]
def __contains__(self, key):
if key is None or '.' not in key:
return dict.__contains__(self, key)
myKey, restOfKey = key.split('.', 1)
if not dict.__contains__(self, myKey):
return False
target = dict.__getitem__(self, myKey)
if not isinstance(target, dotdictify):
return False
return restOfKey in target
def setdefault(self, key, default):
if key not in self:
self[key] = default
return self[key]
def get(self, k, d=None):
if dotdictify.__contains__(self, k):
return dotdictify.__getitem__(self, k)
return d
__setattr__ = __setitem__
__getattr__ = __getitem__
@d0o0b
Copy link

d0o0b commented Oct 20, 2015

Suggestion:

Line 32: return dict.getitem(self, key)
Replace with: return dict.get(self, key, None)

Line 34: target = dict.getitem(self, myKey)
Replace with: target = dict.get(self, myKey, None)

@sanzoghenzo
Copy link

Suggestion from @d0o0b is not good (at least for me), I got many "NoneType" related errors with those lines.
Instead I extended the nested behavior to elements inside lists:

elif isinstance(value, list):
    value = [dotdictify(x) if isinstance(x, dict) and not isinstance(value, dotdictify) else x for x in value]

this lets me access mongoDB documents using dot notation and save them directly. Thanks @einnocent!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment