2016-09-10 4 views
3

Я узнаю о дескрипторах в python. Я хочу написать дескриптор не данных, но класс, имеющий дескриптор как его метод класса, не вызывает пространственный метод __get__, когда я вызываю метод класса. Это мой пример (без __set__):Написание дескриптора без данных в Python

class D(object): 

    "The Descriptor" 

    def __init__(self, x = 1395): 
     self.x = x 

    def __get__(self, instance, owner): 
     print "getting", self.x 
     return self.x 


class C(object): 

    d = D() 

    def __init__(self, d): 
     self.d = d 

А вот как я называю это:

>>>c = C(4) 
>>>c.d 
4 

__get__ класса дескриптора не получает вызов. Но когда я также установил __set__ дескриптор, кажется, активизируются:

class D(object): 

"The Descriptor" 

    def __init__(self, x = 1395): 
     self.x = x 

    def __get__(self, instance, owner): 
     print "getting", self.x 
     return self.x 

    def __set__(self, instance, value): 
     print "setting", self.x 
     self.x = value 

class C(object): 

    d = D() 

    def __init__(self, d): 
     self.d = d 

Теперь я создать C экземпляр:

>>> c=C(4) 
setting 1395 
>>> c.d 
getting 4 
4 

и оба __get__, __set__ присутствуют. Кажется, что мне не хватает некоторых базовых понятий о дескрипторах и способах их использования. Может ли кто-нибудь объяснить это поведение __get__, __set__?

ответ

5

Вы успешно создали надлежащий дескриптор без данных, но затем mask атрибут d, установив атрибут экземпляра.

Потому что это не -Данный дескриптор, атрибут экземпляра выигрывает в этом случае. Когда вы добавляете метод __set__, вы превращаете дескриптор в дескриптор данных, и дескрипторы данных всегда применяются, даже если есть атрибут экземпляра.

От Descriptor Howto:

поведение по умолчанию для доступа к атрибутам, чтобы получить, набор, или удалить атрибут из словаря объекта. Например, a.x имеет цепочку поиска, начиная с a.__dict__['x'], затем type(a).__dict__['x'] и продолжая базовые классы type(a), исключая метаклассы. Если искомое значение является объектом, определяющим один из методов дескриптора, тогда Python может переопределить поведение по умолчанию и вместо этого вызвать дескриптор. Если это происходит в цепочке приоритетов, зависит от того, какие методы дескриптора были определены.

и

Если объект определяет как __get__() и __set__(), считается дескриптором данных. Дескрипторы, которые определяют только __get__(), называются дескрипторами без данных (они обычно используются для методов, но возможны другие виды использования).

Дескрипторы данных и данных, отличные от того, как вычисляются переопределения в отношении записей в словаре экземпляра. Если словарь экземпляра имеет запись с тем же именем, что и дескриптор данных, дескриптор данных имеет приоритет. Если словарь экземпляра имеет запись с тем же именем, что и дескриптор не данных, запись словаря имеет приоритет.

Если удалить атрибут d экземпляра (не установить или удалить его из экземпляра), объект дескриптора получает вызывается:

>>> class D(object): 
...  def __init__(self, x = 1395): 
...   self.x = x 
...  def __get__(self, instance, owner): 
...   print "getting", self.x 
...   return self.x 
... 
>>> class C(object): 
...  d = D() 
... 
>>> c = C() 
>>> c.d 
getting 1395 
1395 

Добавить экземпляр снова атрибут и дескриптор игнорируется поскольку атрибут экземпляра побед:

>>> c.d = 42 # setting an instance attribute 
>>> c.d 
42 
>>> del c.d # deleting it again 
>>> c.d 
getting 1395 
1395 

Также смотрите Invoking Descriptors documentation в Python Datamodel ссылка.