Разница между getattr и getattribute
Я пытаюсь понять, когда использовать __getattr__ или __getattribute__.  Элемент документация упоминает __getattribute__ применяется к классам нового стиля. Что такое классы нового стиля?  
5 ответов:
ключевая разница между
__getattr__и__getattribute__это__getattr__вызывается только в том случае, если атрибут не был найден обычными способами. Это хорошо для реализации резервного варианта для отсутствующих атрибутов и, вероятно, является одним из двух, которые вы хотите.
__getattribute__вызывается перед просмотром фактических атрибутов на объекте, и поэтому может быть сложно реализовать правильно. Вы можете в конечном итоге в бесконечных рекурсий очень легко.классы нового стиля являются производными от
objectстарый стиль классы-это классы в Python 2.x без явного базового класса. Но различие между классами старого и нового стиля не является важным при выборе между__getattr__и__getattribute__.вы почти наверняка хотите
__getattr__.
давайте посмотрим несколько простых примеров как
__getattr__и__getattribute__магические методы.
__getattr__Python вызовет
__getattr__метод, когда вы запрашиваете атрибут, который еще не был определен. В следующем примере мой класс графа нет__getattr__метод. Теперь в основном, когда я пытаюсь получить доступ к обоим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) print(obj1.mymax) print(obj1.mycurrent) --> AttributeError: 'Count' object has no attribute 'mycurrent'теперь мой класс графа и
__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) print(obj1.mymax) print(obj1.mycurrent1)
__getattribute__теперь давайте посмотрим на
__getattribute__метод. Если у вас есть__getattribute__метод в вашем классе, python вызывает этот метод для каждого атрибута независимо от того, существует он или нет. Так зачем же нам__getattribute__способ? Одна из веских причин заключается в том, что вы можете запретить доступ к атрибутам и сделать их более безопасными, как показано в следующем примере.всякий раз, когда кто-то пытается получить доступ к моим атрибутам, которые начинаются с подстроки 'cur' питон поднимает
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) # or you can use ---return super().__getattribute__(item) obj1 = Count(1,10) print(obj1.mymin) print(obj1.mymax) print(obj1.current)важно: чтобы избежать бесконечной рекурсии в
__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) # or you can use ---return super().__getattribute__(item) # note this class subclass object obj1 = Count(1,10) print(obj1.mymin) print(obj1.mymax) print(obj1.current)
классы нового стиля наследуют от
object, или из другого нового класса стиля:class SomeObject(object): pass class SubObject(SomeObject): passклассы старого стиля не делают:
class SomeObject: passЭто относится только к Python 2 - в Python 3 Все вышеперечисленное создаст новые классы стиля.
посмотреть 9. Классы (Python tutorial),NewClassVsClassicClass и в чем разница между старым стилем и новыми классами стилей в Python? для подробности.
Это просто пример, основанный на объяснение Неда Батчелдера.
__getattr__пример:class Foo(object): def __getattr__(self, attr): print "looking up", attr value = 42 self.__dict__[attr] = value return value f = Foo() print f.x #output >>> looking up x 42 f.x = 3 print f.x #output >>> 3 print ('__getattr__ sets a default value if undefeined OR __getattr__ to define how to handle attributes that are not found')и если тот же пример используется с
__getattribute__вы получите >>>RuntimeError: maximum recursion depth exceeded while calling a Python object
классы нового стиля-это те, которые подкласс "объект" (прямо или косвенно). У них есть
__new__метод класса в дополнение к__init__и имеют несколько более рациональное поведение низкого уровня.обычно, вы хотите, чтобы переопределить
__getattr__(Если вы переопределяете либо), в противном случае вам будет трудно поддерживать "себя".ФОО" синтаксис в ваших методах.дополнительная информация: http://www.devx.com/opensource/Article/31482/0/page/4