Разница между 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