2

I am trying to wrap my head around how __getattribute__ and __getattr__ work in Python with respect to uninstantiated classes and subclassing. Specifically I want to capture a getattribute call in the super class and potentially modify it accordingly.

In the following code snippet, I would have expected at least some intermediate print statements when any of the methods are called, but I am not getting anything. The class variable is found and returned but seemingly none of the magic methods are called. Why is that?

class SuperbClass:
    def __getattribute__(self, attr):
        print(f"called in superb, found {attr}")
        # get the attribute via `object`
        return f"{super(SuperbClass, self).__getattribute__(attr)}MODIFIED_IN_SUPER"

    def __getattr__(self, attr):
        self.__getattribute__(attr)

class SubberClass(SuperbClass):
    MyClassVar = "I am a cool message"

    def __getattribute__(self, attr):
        print("called in subber")
        super(SuperbClass, self).__getattribute__(attr)

    def __getattr__(self, attr):
        self.__getattribute__(attr)


if __name__ == '__main__':
    print(SubberClass.MyClassVar)
    # Only prints `I am a cool message`
    inst = SubberClass()
    print(inst.MyClassVar)
    # prints called in subber
    # and prints None

EDIT: updated code to reflect the difference between class and instance

0

1 Answer 1

5

A class's __getattribute__ and __getattr__ handle attribute resolution for instances of the class. If you want to handle attribute resolution for the class itself, you need to define __getattribute__ or __getattr__ on the class's class: its metaclass.

class Meta(type):
    def __getattribute__(self, attr):
        print('*This* prints.')
        return super().__getattribute__(attr)

class Blah(metaclass=Meta):
    MyClassVar = 'blah'

if __name__ == '__main__':
    Blah.MyClassVar
Sign up to request clarification or add additional context in comments.

3 Comments

It's probably useful to mention that __getattr__ would not be called even when using a metaclass that defines the method because MyClassVar can be found in one of the "usual ways", by looking at Blah.__dict__ in this specific case.
Interesting! Can you provide more information about what type does in this context? Alternatively, external resource to read up on are welcome too.
type isn't simply a function that gives you the type of an object (although it does that) - it's also the metaclass of object. Through deep magic, calling type can tell you the type of the passed-in object, or it can construct a new type (i.e., class that has type as its metaclass, which is what you normally get when using a class block). Metaclasses are also classes; here, we create a metaclass by inheriting from the base type, and then use it as a metaclass for Blah.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.