Какая связь между __getattr__ и getattr?

Я знаю, что этот код правильный:

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?


person zjm1126    schedule 22.12.2009    source источник
comment
возможный дубликат Понимание разницы между __getattr__ и __getattribute__   -  person Trilarion    schedule 18.02.2015
comment
@Trilarion, который не является подходящим дубликатом для этого вопроса   -  person Antti Haapala    schedule 20.02.2015


Ответы (3)


Ответ Алекса был хорошим, но он предоставил вам пример кода, так как вы его просили :)

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, чтобы получить атрибуты

person Kimvais    schedule 22.12.2009
comment
Будьте осторожны, если вы используете __getattr__, потому что он ломает встроенный модуль copy, если вы также не реализуете __copy__ и __deepcopy__ для своего класса. Мне потребовалось некоторое время, чтобы отследить эту ошибку... Во всяком случае, на 2.7 - person Kassym Dorsel; 23.10.2013

getattr — это встроенная функция, принимающая (как минимум) два аргумента: объект, из которого вы получаете атрибут, и строковое имя атрибута.

Если имя строки является константой, скажем, 'foo', getattr(obj, 'foo') точно то же самое, что и obj.foo.

Таким образом, основной вариант использования встроенной функции getattr — это когда у вас есть имя атрибута не как константа, а как переменная. Второй важный вариант использования — это когда вы передаете ему три аргумента, а не только два: в этом случае, если атрибут отсутствует в объекте, getattr возвращает третий аргумент «по умолчанию», а не вызывает исключение.

__getattr__ — это специальный метод, определенный в классе, который вызывается, когда запрашивается какой-либо атрибут экземпляра этого класса, и другие обычные способы предоставления этого атрибута (через __dict__ экземпляра, слоты, свойства и т. д.) не увенчались успехом. . Вы можете определить его, например, когда хотите делегировать другим объектам поиск атрибутов, которые в противном случае не определены.

Таким образом, ваш второй пример неверен, потому что встроенная функция getattr никогда не может быть вызвана с одним аргументом.

Третий терпит неудачу, потому что словарь, из которого вы пытаетесь «получить атрибут», не имеет этого атрибута — в нем есть элементы, которые, конечно, полностью не пересекаются с атрибутами.

person Alex Martelli    schedule 22.12.2009
comment
Хотя ваш ответ превосходен, @zjm1126 хотел получить образец кода, потому что его английский не так хорош. - person Kimvais; 22.12.2009

__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__'"

К сожалению, сейчас невозможно получить доступ к av!

person steveha    schedule 22.12.2009
comment
+1 за упоминание getattribute, о котором, я думаю, и был вопрос. - person kibitzer; 22.12.2009
comment
Хорошее и простое объяснение getattribute, которое всегда казалось мне непонятным. - person Taurus Olson; 15.11.2011