Best and complete implementation
from typing import Anyclass DotDict(dict):""" dot.notation access to dictionary attributes""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for key, value in self.items(): if isinstance(value, dict): self[key] = DotDict(value) def __setitem__(self, key: Any, item: Any) -> None: if isinstance(item, dict): item = DotDict(item) super().__setitem__(key, item) def __getitem__(self, key: Any) -> Any: return super().__getitem__(key) def __setattr__(self, key: Any, item: Any) -> None: return self.__setitem__(key, item) def __getattr__(self, key: Any) -> Any: return self.__getitem__(key) def __missing__(self, key: Any) -> str: raise KeyError(f"DotDict object has no item '{key}'") def __getstate__(self) -> dict: return self def __setstate__(self, state: dict) -> None: self.update(state) self.__dict__ = self def __delattr__(self, item: Any) -> None: self.__delitem__(item) def __delitem__(self, key: Any) -> None: super().__delitem__(key)
Test:
# Create a DotDict instanced = DotDict()# Test __setattr__ methodd.foo = "bar"assert d.foo == "bar"# Test __getattr__ methodassert d.foo == "bar"# Test __getitem__ methodassert d["foo"] == "bar"# Test __setitem__ methodd["baz"] = "qux"assert d.baz == "qux"# Test nested dictionariesd.nested = {"nested_key": "nested_value"}assert d.nested.nested_key == "nested_value"# Test nested updated.nested.nested_key = "new_value"assert d.nested.nested_key == "new_value"# Test __delattr__ methoddel d.footry: _ = d.fooexcept KeyError as e: assert e.args[0] == "DotDict object has no item 'foo'"# Test __delitem__ methoddel d["baz"]try: _ = d.bazexcept KeyError as e: assert e.args[0] == "DotDict object has no item 'baz'"# Test __getstate__ methodstate = d.__getstate__()assert state == {"nested": {"nested_key": "new_value"}}# Test __setstate__ methodnew_d = DotDict()new_d.__setstate__(state)assert new_d.nested.nested_key == "new_value"