python – Difference between __getattr__ and __getattribute__

Question:

I'm trying to figure out when to use __getattr__ and when to __getattribute__ . The documentation mentions that __getattribute__ applies to new style classes. What are New Style Classes?

Translation question Difference between __getattr__ vs __getattribute__ from contributor Yarin

Answer:

Let's take a look at some simple examples of using __getattr__ and __getattribute__ .

__getattr__

Python will call the __getattr__ method whenever you request an attribute that has not yet been defined. In the following example, my Count class does not have a __getattr__ method. Now in main when I try to access obj1.mymin and obj1.mymax everything works fine. But when I try to access obj1.mycurrent attribute – Python gives me

AttributeError: 'Count' object has no attribute 'mycurrent'
class Count():
    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax

obj1 = Count(1,10)
print(obj1.mymin)      # 1
print(obj1.mymax)      # 10
print(obj1.mycurrent)  # AttributeError: 'Count' object has no attribute 'mycurrent'

Now my Count class has a __getattr__ method. Now when I try to access obj1.mycurrent python gives me back everything I have implemented in my __getattr__ . In my example, every time I try to call an attribute that doesn't exist, python creates that attribute and sets it to an integer value of 0.

class Count:
    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax    

    def __getattr__(self, item):
        self.__dict__[item]=0
        return 0

obj1 = Count(1,10)
print(obj1.mymin)       # 1
print(obj1.mymax)       # 10
print(obj1.mycurrent1)  # 0

__getattribute__

Now let's take a look at the __getattribute__ method. If your class has a __getattribute__ method, python calls that method on every attribute whether it exists or not. So why do we need the __getattribute__ method? One good reason is that you can deny access to attributes and make them more secure, as shown in the following example.

Whenever someone tries to access attributes starting with the substring 'cur' python throws an AttributeError . Otherwise, it returns this attribute.

class Count:

    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax
        self.current=None

    def __getattribute__(self, item):
        if item.startswith('cur'):
            raise AttributeError
        return object.__getattribute__(self,item) 
        # либо можете использовать 
        # return super().__getattribute__(item)

obj1 = Count(1,10)
print(obj1.mymin)    # 1
print(obj1.mymax)    # 10
print(obj1.current)  # AttributeError

Important: to avoid endless recursion in __getattribute__ , its implementation must always call a base class method with the same name to access any attributes it needs. For instance:

object.__getattribute__(self, name)

or

super().__getattribute__(item)  # и нет self.__dict__[item]

If your class contains __getattr__ and __getattribute__ magic methods, then __getattribute__ is called __getattribute__ . But if __getattribute__ raises an AttributeError exception, then the exception will be ignored and the __getattr__ method will be called.

class Count(object):

    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax
        self.current=None

    def __getattr__(self, item):
            self.__dict__[item]=0
            return 0

    def __getattribute__(self, item):
        if item.startswith('cur'):
            raise AttributeError
        return object.__getattribute__(self,item)
        # или вы можете использовать return super().__getattribute__(item)

obj1 = Count(1,10)
print(obj1.mymin)    # 1
print(obj1.mymax)    # 10
print(obj1.current)  # 0

Translation of the answer from participant N Randhawa

Scroll to Top