The __getattribute__() method is invoked when an attribute of an object is being accessed for example when using the dot notation.

This is the method that gets actually called when you access an object's attribute such as a variable or a method. So in an attempt to access an attribute i.e x.y, Python in the background calls x.__getattribute__(y).

Similarly the method gets called when we use the  builtin getattr() function to access the attributes dynamically. 

L = [5, 2, 1, 4, 5]
L.__getattribute__("sort")() # Same as L.sort() or getattr(L, "sort")()
print(L)

S = "pynerds"
print(S.__getattribute__("upper")()) #Same as print(S.upper()) or getattr(S, "upper")()

Overriding the __getattribute__() method for custom objects 

We can override the __getattribute__() method for custom objects by providing a custom implementation in the class definition. . By doing this we can be  able to define custom logic for how attributes are retrieved. 

class MyClass:
    def __getattribute__(self, attr):
        #custom implementation
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __getattribute__(self, attr):
         if attr == "age":
             return "Sorry, you are not allowed to view this person's age"
         return super().__getattribute__(attr)
p = Person("Mary", 30)

print(p.name)
print(p.age)

As you can see above, the method allows us to intercept and customize the attributes value. However, you should always remember to call the super.__getattribute__() method after overriding the __getattribute__() method , otherwise you will be required to implement the logic for all possible attributes and methods for the object.

When to override the __getattribute__() Function.

In most programming scenarios, you will rarely need to override the __getattribute__() method.  It should not be used as a substitute for the __getattr__() method, which is more commonly used for dynamic attribute access. It is also not considered a good practice to use the method for changing the behavior of existing attributes, and should therefore be implemented only when absolutely necessary.

We can override this method in order to get the following functionalities:

  • To customize the behavior of attribute access.
  • To intercept the attribute access and modify the attribute or value before returning it.
  • To provide a dynamic way for accessing attributes that are not available in the instance.
  • To provide an efficient way for implementing descriptors, properties, and other special methods.
  • To create a “virtual” attribute that is not stored as a variable but is computed on demand.

Note: This method is distinct from the __getattr__() method, which you can use to access an attribute of an object, even if it is not explicitly defined in the class.

Overriding the __getattr__() method is more permissive as it only gets called when the __getattribute__() method fails to locate the requested attribute in the object's namespace.

So before overriding the __getattribute__() method always first consider whether defining the __getattr__() method is actually more fit. In most cases, it usually is.