How to call setattr before getattr in nested calling

Viewed 29

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

0 Answers
Related