Разница между getattr и getattribute
Я пытаюсь понять, когда использовать __getattr__
или __getattribute__
. The документация упоминает __getattribute__
применяется к классам нового стиля. Что новый-стиль-классы?
5 ответов
ключевое различие между __getattr__
и __getattribute__
это __getattr__
вызывается только в случае, если атрибут не найден обычными способами. Это хорошо для реализации резервного копирования отсутствующих атрибутов и, вероятно, является одним из двух, которые вы хотите.
__getattribute__
вызывается перед просмотром фактических атрибутов объекта, и поэтому может быть сложно реализовать правильно. Вы можете очень легко попасть в бесконечные рекурсии.
классы нового стиля являются производными от object
старый стиль классы-это классы в Python 2.x без явного базового класса. Но различие между классами старого и нового стилей не является важным при выборе между __getattr__
и __getattribute__
.
вы почти наверняка хотите __getattr__
.
давайте посмотрим несколько простых примеров как __getattr__
и __getattribute__
магические методы.
__getattr__
Python вызовет __getattr__
метод, когда вы запрашиваете атрибут, который еще не был определен. В следующем примере мой класс графа нет __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)
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' 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)
# 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__
вызывается первой. Но если ... --5--> поднимает
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 учебник),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__
(Если вы переопределяете либо), в противном случае вам будет трудно поддерживать "себя".синтаксис foo " в ваших методах.
дополнительная информация: http://www.devx.com/opensource/Article/31482/0/page/4