Использование getattr для класса с дескриптором данных

#python #python-2.7 #class #getattr

#python #python-2.7 #класс #getattr

Вопрос:

При использовании дескрипторов данных при построении классов я столкнулся со странным поведением функции getattr в классе.

 # this is a data descriptor
class String(object):
    def __get__(self, instance, owner):
        pass
    def __set__(self, instance, value):
        pass

# This defines a class A with 'dot' notation support for attribute 'a'
class A(object):
    a = String()

obj = A()
assert getattr(A, 'a') is A.__dict__['a']
# This raises AssertionError
  

LHS возвращает пустую строку, в то время как RHS возвращает экземпляр String . Я думал getattr , что объект должен был получить значение для ключа внутри __dict__ . Как getattr функция работает с объектом класса?

Комментарии:

1. Вы уверены, что он возвращает пустую строку, а не None ?

2. LHS точно возвращает пустую строку ? Как я пытаюсь, он возвращается None . А почему бы и нет? Вы говорите об этом в дескрипторе!

3. Кстати: A.a это не то же самое, что A.__dict__['a'] . Только первый запускает «весь механизм атрибутов».

4. So getattr(obj, 'a') и getattr(A, ‘a’)` чем-то похожи? Оказывается, в моем случае дескриптор имел значение по умолчанию » set». Итак, единственный способ восстановить объект дескриптора — это проверить класс __dict__ напрямую?

Ответ №1:

getattr(A, 'a') так называется запуск протокола дескриптора, даже для классов String.__get__(None, A) .

Это возвращается None , потому что ваш String.__get__() метод не имеет явного return оператора.

Из дескриптора Как:

Для классов механизм, в type.__getattribute__() котором преобразуется B.x в B.__dict__['x'].__get__(None, B) .

getattr(A, 'a') это просто динамический A.a отсюда, поэтому A.__dict__['x'].__get__(None, A) выполняется, поэтому вы не получаете то же самое, A.__dict__['x'] что и .

Если вы ожидали, что он вернет сам объект дескриптора, вам придется сделать это явно; instance None в этом случае будет установлено значение:

 class String(object):
    def __get__(self, instance, owner):
        if instance is None:
            return self
    def __set__(self, instance, value):
        pass
  

Это то, что property делает объект дескриптора.

Обратите внимание, что owner аргумент to descriptor.__get__ является необязательным; если он не установлен, вы должны использовать type(instance) вместо него.

Ответ №2:

getattr(A, 'a') то же A.a самое, что и . Это вызывает соответствующий дескриптор, если он присутствует. Таким образом, он предоставляет значение, представленное дескриптором, которое является None .