Я пытаюсь понять разницу между ними, __getattr__
и __getattribute__
, тем не менее, мне это не удается.
Ответ на вопрос переполнения стека Разница между __getattr__
VS__getattribute__
говорит:
__getattribute__
вызывается перед просмотром фактических атрибутов объекта, и поэтому может быть сложно реализовать правильно. Вы можете очень легко попасть в бесконечные рекурсии.
Я понятия не имею, что это значит.
Тогда это говорит:
Вы почти наверняка хотите
__getattr__
.
Зачем?
Я читал, что если __getattribute__
не получается, __getattr__
называется. Так почему же два разных метода делают одно и то же? Если мой код реализует новые классы стилей, что я должен использовать?
Я ищу несколько примеров кода, чтобы прояснить этот вопрос. Я использовал Google в меру своих возможностей, но ответы, которые я нашел, не обсуждают проблему полностью.
Если есть какая-либо документация, я готов это прочитать.
источник
Ответы:
Сначала некоторые основы.
С объектами вам нужно разобраться с его атрибутами. Обычно мы делаем
instance.attribute
. Иногда нам нужно больше контроля (когда мы заранее не знаем имя атрибута).Например,
instance.attribute
стал быgetattr(instance, attribute_name)
. Используя эту модель, мы можем получить атрибут, указав attribute_name в виде строки.Использование
__getattr__
Вы также можете указать классу, как обращаться с атрибутами, которыми он явно не управляет, и делать это с помощью
__getattr__
метода.Python будет вызывать этот метод всякий раз, когда вы запрашиваете атрибут, который еще не был определен, поэтому вы можете определить, что с ним делать.
Классический вариант использования:
Предостережения и использование
__getattribute__
Если вам нужно перехватить каждый атрибут независимо от того, существует он или нет , используйте
__getattribute__
вместо этого. Разница в том, что вызывается__getattr__
только для атрибутов, которые на самом деле не существуют. Если вы устанавливаете атрибут напрямую, ссылка на этот атрибут будет извлекать его без вызова__getattr__
.__getattribute__
называется все время.источник
getattr(instance, attribute_name)
." Не должно ли это быть__getattribute__(instance, attribute_name)
?getattr
- это встроенная функция.getattr(foo, 'bar')
эквивалентноfoo.bar
.__getattr__
онobject
__getattribute__
вызывается всякий раз, когда происходит доступ к атрибуту.Это приведет к бесконечной рекурсии. Виновником здесь является линия
return self.__dict__[attr]
. Давайте представим (это достаточно близко к правде), что все атрибуты хранятсяself.__dict__
и доступны по их имени. Линияпытается получить доступ к
a
атрибутуf
. Это звонкиf.__getattribute__('a')
.__getattribute__
затем пытается загрузитьself.__dict__
.__dict__
является атрибутомself == f
и поэтому вызывает Python,f.__getattribute__('__dict__')
который снова пытается получить доступ к атрибуту'__dict__
'. Это бесконечная рекурсия.Если
__getattr__
бы был использован вместо этого, тоf
имеетa
атрибут.f.b
), то он не был бы вызван для поиска,__dict__
потому что он уже существует и__getattr__
вызывается только в случае сбоя всех других методов поиска атрибута .«Правильный» способ писать выше класс , используя
__getattribute__
этоsuper(Foo, self).__getattribute__(attr)
привязывает__getattribute__
метод «ближайшего» суперкласса (формально, следующего класса в порядке разрешения методов или MRO) к текущему объекту,self
а затем вызывает его и позволяет выполнить эту работу.Все эти проблемы можно избежать, используя
__getattr__
Python, который делает это нормально, пока атрибут не найден. В этот момент Python передает управление вашему__getattr__
методу и позволяет ему что-то придумать.Также стоит отметить, что вы можете столкнуться с бесконечной рекурсией
__getattr__
.Я оставлю это как упражнение.
источник
Я думаю, что другие ответы проделали большую работу по объяснению разницы между
__getattr__
и__getattribute__
, но одна вещь, которая может быть неясной, это то, почему вы хотели бы использовать__getattribute__
. Крутая вещь в__getattribute__
том, что она по сути позволяет перегружать точку при доступе к классу. Это позволяет вам настроить доступ к атрибутам на низком уровне. Например, предположим, что я хочу определить класс, где все методы, которые принимают только аргумент self, рассматриваются как свойства:И от интерактивного переводчика:
Конечно, это глупый пример, и вы, вероятно, никогда не захотите этого делать, но он показывает вам силу, которую вы можете получить от переопределения
__getattribute__
.источник
Я прошел через отличное объяснение других. Тем не менее, я нашел простой ответ из этого блога Python Magic Methods и
__getattr__
. Все следующее оттуда.Используя
__getattr__
магический метод, мы можем перехватить поиск несуществующего атрибута и сделать что-нибудь, чтобы он не потерпел неудачу:Но если атрибут существует,
__getattr__
не будет вызван:__getattribute__
похоже__getattr__
, с важным отличием, которое__getattribute__
будет перехватывать КАЖДЫЙ поиск атрибута, не имеет значения, существует ли атрибут или нет.В этом примере
d
объект уже имеет значение атрибута. Но когда мы пытаемся получить к нему доступ, мы не получаем первоначальное ожидаемое значение («Python»); мы просто получаем то, что__getattribute__
вернули. Это означает, что мы фактически потеряли атрибут value; оно стало «недоступным».источник