Skip to content

Instantly share code, notes, and snippets.

@vstoykov
Last active August 30, 2018 14:11
Show Gist options
  • Save vstoykov/3c3367e746ee3ccdc26e030f869cfbd5 to your computer and use it in GitHub Desktop.
Save vstoykov/3c3367e746ee3ccdc26e030f869cfbd5 to your computer and use it in GitHub Desktop.
Simple dict sucblass for making it possible to access keys as attributes
from collections import defaultdict
class DictObject(dict):
"""
Simple dict subclass for making it possible to to access keys as attributes
This class can be used as object_hook when deserializing JSON for easy
access to attributes of the JSON objects.
Example::
>>> import json
>>> result = json.loads('{"a": 1, "b": 2}', object_hook=DictObject)
>>> result
DictObject({'a': 1, 'b': 2})
>>> result.a == result['a'] == 1
True
>>> result.b == result['b'] == 2
True
>>> result.c = 3
>>> result.c == result['c'] == 3
True
>>> result
DictObject({'a': 1, 'b': 2, 'c': 3})
>>> del result.a
>>> result
DictObject({'b': 2, 'c': 3})
>>> result.a
Traceback (most recent call last):
...
AttributeError: 'DictObject' object has no attribute 'a'
>>> del result.a
Traceback (most recent call last):
...
AttributeError: 'DictObject' object has no attribute 'a'
"""
# We are defining empty __slots__ because we will use the keys in
# self as attributes and we do not want the resulting object to
# have __dict__ which will waste memory.
__slots__ = ()
def __getattr__(self, attr):
try:
return self[attr]
except KeyError:
raise AttributeError("'{}' object has no attribute {!r}".format(self.__class__.__name__, attr))
def __setattr__(self, attr, val):
self[attr] = val
def __delattr__(self, attr):
try:
del self[attr]
except KeyError:
raise AttributeError("'{}' object has no attribute {!r}".format(self.__class__.__name__, attr))
def __dir__(self):
return list(sorted(set(super().__dir__()).union(self)))
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, dict.__repr__(self))
class DefaultDictObject(DictObject, defaultdict):
"""
Implements DictObject as defaultdict
Example::
>>> d = DefaultDictObject(list)
>>> d
DefaultDictObject(<class 'list'>, {})
>>> [] == d.something == d['something']
True
>>> d = DefaultDictObject(list, {'a': [1, 2, 3]})
>>> d
DefaultDictObject(<class 'list'>, {'a': [1, 2, 3]})
>>> [1, 2, 3] == d.a == d['a']
True
"""
# We are redefining __slots__ to be empty because of the same reason
# as in DictObject - to not waste memory.
__slots__ = ()
def __repr__(self):
return '{}({!r}, {})'.format(self.__class__.__name__,
self.default_factory,
dict.__repr__(self))
if __name__ == "__main__":
import doctest
doctest.testmod()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment