Я пытаюсь понять, когда использовать __getattr__, а когда __getattribute__. В документации упоминается, что __getattribute__ применяется к классам нового стиля. Что такое классы нового стиля? Перевод вопрос Difference between __getattr__ vs __getattribute__ от участника Yarin
Ответ Давайте посмотрим на несколько простых примеров использования __getattr__ и __getattribute__. __getattr__ Python будет вызывать метод __getattr__ всякий раз, когда вы запросите атрибут, который еще не был определен. В следующем примере мой класс Count не имеет метода __getattr__. Теперь в main, когда я пытаюсь получить доступ к атрибутам obj1.mymin и obj1.mymax все работает нормально. Но когда я пытаюсь получить доступ к атрибуту obj1.mycurrent - Python выдает мне 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' Теперь у моего класса Count есть метод __getattr__. Теперь, когда я пытаюсь получить доступ к obj1.mycurrent python возвращает мне все, что я реализовал в своем __getattr__. В моем примере каждый раз, когда я пытаюсь вызвать атрибут, которого не существует, python создает этот атрибут и устанавливает ему целочисленное значение 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__ Теперь давайте посмотрим на метод __getattribute__. Если в вашем классе есть метод __getattribute__, python вызывает этот метод для каждого атрибута независимо от того, существует он или нет. Так зачем же нам нужен метод __getattribute__? Одна из веских причин заключается в том, что вы можете запретить доступ к атрибутам и сделать их более безопасными, как показано в следующем примере. Всякий раз, когда кто-то пытается получить доступ к атрибутам, начинающимся с подстроки 'cur' python вызывает исключение AttributeError. В противном случае он возвращает этот атрибут. 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 Важно: чтобы избежать бесконечной рекурсии в __getattribute__, его реализация всегда должна вызывать метод базового класса с тем же именем для доступа к любым необходимым ему атрибутам. Например: object.__getattribute__(self, name) или super().__getattribute__(item) # и нет self.__dict__[item] Если ваш класс содержит магические методы __getattr__ и __getattribute__, то сначала вызывается __getattribute__. Но если __getattribute__ вызывает исключение AttributeError, то исключение будет проигнорировано и будет вызван метод __getattr__. 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 Перевод ответа от участника N Randhawa