I would like to create a nested structure and can be freely edited.
For example, for a e = Example(), I can set e.a.b.c = 1 and it will create a = Example(), b = Example() for me, but if I access something does not exists like e.a.b.d, it should throw an AttributeError.
I found that, before calling __setattr__, __getattr__ is first called to get e.a.b. One workaround is to create and return an Example upon AttributeError, but it works as a defaultdict and won't raise exception when getting attributes.
class Example:
def get(self, name: str, default: Optional[Any] = None) -> Any:
@wraps(self.get)
def get(self, name):
if '.' in name:
name, rest = name.split('.', 1)
return getattr(self[name], rest)
elif getattr(self, "_frozen", False):
try:
return super().__getattribute__(name)
except AttributeError:
super().__setattr__(name, Example())
return self[name]
return super().__getattribute__(name)
if default is not None:
try:
return get(self, name)
except AttributeError:
return default
return get(self, name)
__getitem__ = get
__getattr__ = get
def set(self, name: str, value: Any) -> None:
if '.' in name:
name, rest = name.split(self.delimiter, 1)
if not hasattr(self, name):
setattr(self, name, Example())
setattr(self[name], rest, value)
else:
super().__setattr__(name, value)
__setitem__ = set
__setattr__ = set