Я знаю, что этот код является правильным:
class A:
def __init__(self):
self.a = 'a'
def method(self):
print "method print"
a = A()
print getattr(a, 'a', 'default')
print getattr(a, 'b', 'default')
print getattr(a, 'method', 'default')
getattr(a, 'method', 'default')()
И это неправильно:
# will __getattr__ affect the getattr?
class a(object):
def __getattr__(self,name):
return 'xxx'
print getattr(a)
Это также неправильно:
a={'aa':'aaaa'}
print getattr(a,'aa')
Где мы должны использовать __getattr__
и getattr
?
Ответ Алекса был хорош, но предоставив вам пример кода, так как вы просили об этом : )
class foo:
def __init__(self):
self.a = "a"
def __getattr__(self, attribute):
return "You asked for %s, but I'm giving you default" % attribute
>>> bar = foo()
>>> bar.a
'a'
>>> bar.b
"You asked for b, but I'm giving you default"
>>> getattr(bar, "a")
'a'
>>> getattr(bar, "b")
"You asked for b, but I'm giving you default"
Итак, в коротком ответе
Вы используете
__getattr__
для определения того, как работать с атрибутами, которые не найдены
и
getattr
для получения атрибутов
getattr
- это встроенная функция, принимающая (как минимум) два аргумента: объект, с которого вы получаете атрибут, и строковое имя атрибута.
Если имя строки - константа, скажем 'foo'
, то getattr(obj, 'foo')
- это точно такая же вещь , как и obj. foo
.
Итак, основной случай использования встроенной функции getattr
- это когда имя атрибута не является константой, а переменной. Вторым важным случаем использования является передача трёх аргументов, а не только двух: в этом случае, если атрибут отсутствует в объекте, getattr
возвращает третий, "по умолчанию", аргумент, вместо того, чтобы вызывать исключение.
__getattr__
- это специальный метод, определённый в классе, который вызывается, когда запрашивается какой-то атрибут экземпляра этого класса, и другие обычные способы поставки этого атрибута (через экземпляр __dict__
, слоты, свойства и т.д.) - всё это не работает. Вы можете определить его, например, когда хотите делегировать поиск других атрибутов другим объектам.
Итак, ваш второй пример неверен, потому что встроенный getattr
может никогда не вызываться с одним аргументом.
Третий пример не работает, потому что словарь, из которого вы пытаетесь "получить атрибут", не имеет этого атрибута - в нем есть элементы, которые, конечно же, полностью отделены от атрибутов.
.__getattr__()
- специальная функция метода, которую можно определить. Когда поиск члена не удается, вызывается эта функция.
getattr()
является функцией, которую можно вызвать для попытки поиска члена. Если поиск завершится успешно, Вы получите член (возможно, объект функции метода или, возможно, объект атрибута данных). getattr()
также может возвращать значение по умолчанию в случае неудачи поиска.
Если Вы объявите функцию-член __getattr__()
, Вы можете сделать ее успешной иногда, или Вы можете сделать ее успешной каждый раз.
class A(object):
def __getattr__(self, name):
return "I pretend I have an attribute called '%s'" % name
a = A()
print a.foo # prints "I pretend I have an attribute called 'foo'"
Python также имеет __getattribute__()
, которая является всегда вызываемой при каждом поиске. Это очень опасно, потому что это может сделать невозможным нормальный доступ к членам.
class A(object):
def __init__(self, value):
self.v = value
def __getattribute__(self, name):
return "I pretend I have an attribute called '%s'" % name
a = A(42)
print a.v # prints "I pretend I have an attribute called 'v'"
print a.__dict__["v"] # prints "I pretend I have an attribute called '__dict__'"
Ой, теперь невозможно получить доступ к a.v!
.