Implementing a __class_getattribute__ for using a ClassName.attr notation

Implementation of a __class_getattribute__

Adding a method to a class called __getattribute__ allows the user to modify how items are grabbed from a class, as shown below:

class A:
    def __getattribute__(self, attr):
        print(attr)

a = A()
a.print_me

# outputs "print_me"

However there is no class equivalent so the following code would raise an attribute error

class A:
    def __getattribute__(self, attr):
        print(attr)

A.error
# raises an attribute error

Pitch

The implementation of this would help with the singleton pattern (where only version of the class can exist at any one point). Lets suppose we have a class called “settings” and we only want one world to exist at any given point. We could pass the class around in functions and self impose that we can have one version of that class but that gets messy. Other suggestions include changing the __new__ attribute of the class and return an existing instance if possible. This approach still requires the user to use the initialization syntax, className() which can make it look like the user is making multiple instances of one class. The best approach would be to just reference the class name and then get what attributes you want.

Pass class instance around approach

def function(settings):
    settings.a = True
    settings.b = False
    settings.c = 5

Make new instance of class each time

def function():
    Settings().a = True
    Settings().b = False
    Settings().c = 5

Proposed way

def function():
    Settings.a = True
    Settings.b = False
    Settings.c = 5

The implementation of the “Settings” class to enable this would look like:

class Settings:
    __instance = None

    def __class_getattribute__(cls, attribute):
        if cls.__instance is None:
            cls.__instance = cls()

        return getattr(cls, attribute)

Overall, the __class_getattribute__ is very similar to __class_getattr__ but it is for the dot notation (a.b).

Does using a metaclass work?

class MetaSettings(type):
    def __getattribute__(cls, attribute):
        print(attribute)


class Settings(metaclass=MetaSettings):
    pass

if __name__ == "__main__":
    Settings.a
    Settings.b
2 Likes

That’s really not a strong use-case, but as has already been mentioned, a metaclass can do this for you.

But I would also recommend looking into dataclasses. Drop the requirement for there to be a singleton, and a dataclass is perfect; plus, it lets you have separate configs - if you’re always looking up your settings from this object, you can easily switch to your test config, your staging config, etc, just by replacing one object.