Data Model

Attribute Access

Attribute hooks customize lookup, missing attributes, and assignment.

Normal initialization still needs to set real attributes. Calling object.__setattr__ avoids recursing through your own hook.

Source

class Settings:
    def __init__(self, values):
        self._values = dict(values)

settings = Settings({"theme": "dark"})
print(settings._values)

Output

{'theme': 'dark'}
obj.xinstance __dict__class __dict____getattr__
obj.x checks instance __dict__, then class __dict__, then __getattr__; the first hit wins.

__getattr__ runs only for missing attributes, so it can provide fallback lookup.

Source

class Settings:
    def __init__(self, values):
        self._values = dict(values)

    def __getattr__(self, name):
        try:
            return self._values[name]
        except KeyError as error:
            raise AttributeError(name) from error

settings = Settings({"theme": "dark"})
print(settings.theme)

Output

dark

__setattr__ intercepts assignment. This example stores public names in the backing dictionary.

Source

class Settings:
    def __init__(self, values):
        self._values = dict(values)

    def __setattr__(self, name, value):
        if name.startswith("_"):
            object.__setattr__(self, name, value)
        else:
            self._values[name] = value

settings = Settings({"theme": "dark"})
settings.volume = 7
print(settings._values["volume"])

Output

7

Notes

See also

Run the complete example

Example code

Expected output

dark
7

Execution time appears here after you run the example.