Skip to content

Instantly share code, notes, and snippets.

@gyli
Last active November 14, 2023 17:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gyli/c91d84fdf26165209452c05dd4068927 to your computer and use it in GitHub Desktop.
Save gyli/c91d84fdf26165209452c05dd4068927 to your computer and use it in GitHub Desktop.
Map dict to object attributes in Python
class DictObjMap(dict):
"""
Converts dict to object attributes for easier value fetching
It supports fetching nested dict and list value like `obj.array[0].item`
Invalid list index and non-existing key will throw out IndexError and KeyError like native list and dict
Can be migrated to dataclasses once Python is upgraded to >=3.7
Side effect:
Namespace of builtin dict method attributes is overridden with config keys, only other than get().
Use dict() when calling dict methods, like `dict(obj.array[0].item).items()`
"""
def __init__(self, *args, **kwargs):
super(DictObjMap, self).__init__(*args, **kwargs)
for arg in args:
if isinstance(arg, dict):
for k, v in arg.items():
if isinstance(v, dict):
v = DictObjMap(v)
elif isinstance(v, list):
self.__convert(v)
self[k] = v
if kwargs:
for k, v in kwargs.items():
if isinstance(v, dict):
v = DictObjMap(v)
elif isinstance(v, list):
self.__convert(v)
self[k] = v
def __convert(self, v):
for elem in range(0, len(v)):
if isinstance(v[elem], dict):
v[elem] = DictObjMap(v[elem])
elif isinstance(v[elem], list):
self.__convert(v[elem])
def __getattr__(self, attr):
"""
config.does_not_exist raises error and hasattr(config, 'key_not_exists') returns False
Change to return self.get(attr) if returning None is preferred
"""
try:
return self[attr]
except KeyError:
classname = type(self).__name__
msg = f'{classname!r} object has no attribute {attr!r}'
raise AttributeError(msg)
def __setattr__(self, key, value):
self.__setitem__(key, value)
def __setitem__(self, key, value):
super(DictObjMap, self).__setitem__(key, value)
self.__dict__.update({key: value})
def __delattr__(self, item):
self.__delitem__(item)
def __delitem__(self, key):
super(DictObjMap, self).__delitem__(key)
del self.__dict__[key]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment