Created
September 5, 2012 09:03
-
-
Save majgis/3633724 to your computer and use it in GitHub Desktop.
DictWrap: Create or access massive nested dictionaries with ease.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class DictWrap(object): | |
""" Wrap an existing dict, or create a new one, and access with either dot | |
notation or key lookup. | |
The attribute _data is reserved and stores the underlying dictionary. | |
When using the += operator with create=True, the empty nested dict is | |
replaced with the operand, effectively creating a default dictionary | |
of mixed types. | |
args: | |
d({}): Existing dict to wrap, an empty dict is created by default | |
create(True): Create an empty, nested dict instead of raising a KeyError | |
example: | |
>>>dw = DictWrap({'pp':3}) | |
>>>dw.a.b += 2 | |
>>>dw.a.b += 2 | |
>>>dw.a['c'] += 'Hello' | |
>>>dw.a['c'] += ' World' | |
>>>dw.a.d | |
>>>print dw._data | |
{'a': {'c': 'Hello World', 'b': 4, 'd': {}}, 'pp': 3} | |
""" | |
def __init__(self, d=None, create=True): | |
if d is None: | |
d = {} | |
supr = super(DictWrap, self) | |
supr.__setattr__('_data', d) | |
supr.__setattr__('__create', create) | |
def __getattr__(self, name): | |
try: | |
value = self._data[name] | |
except KeyError: | |
if not super(DictWrap, self).__getattribute__('__create'): | |
raise | |
value = {} | |
self._data[name] = value | |
if hasattr(value, 'items'): | |
create = super(DictWrap, self).__getattribute__('__create') | |
return DictWrap(value, create) | |
return value | |
def __setattr__(self, name, value): | |
self._data[name] = value | |
def __getitem__(self, key): | |
try: | |
value = self._data[key] | |
except KeyError: | |
if not super(DictWrap, self).__getattribute__('__create'): | |
raise | |
value = {} | |
self._data[key] = value | |
if hasattr(value, 'items'): | |
create = super(DictWrap, self).__getattribute__('__create') | |
return DictWrap(value, create) | |
return value | |
def __setitem__(self, key, value): | |
self._data[key] = value | |
def __iadd__(self, other): | |
if self._data: | |
raise TypeError("A Nested dict will only be replaced if it's empty") | |
else: | |
return other | |
def __call__(self, keys, default=0): | |
"""Normalize dictionary | |
Recursively adds keys only to dicts that contain non-dict | |
values, ie. if all values are dicts, then keys are not added | |
args: | |
keys: iterable of dictionary keys to create | |
default: default value for each key (deep copy) | |
""" | |
root_normalized = False | |
for child in self._data.values(): | |
if isinstance(child, Mapping): | |
DictWrap(child)(keys, default) | |
elif not root_normalized: | |
for key in keys: | |
if self._data.get(key, None) is None: | |
self._data[key] = deepcopy(default) | |
root_normalized = True |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment