2015-05-24 4 views
2

Предположим, что у меня есть класс следующим образом:Вопросы о деталях @property в Python

class MyClass(object): 

    def __init__(self, value=None): 
     self.attr = value 

    @property 
    def attr(self): 
     # This acts as a getter? 
     # Let's call the function "attr_1" as alias 
     return self.__attr 

    @attr.setter 
    def attr(self, value): 
     # This acts as a setter? 
     # Let's call the function "attr_2" as alias 
     self.__attr = value 


inst = MyClass(1) 

Я прочитал Documentation on Descriptor и посмотрел на реализацию property класса.

Насколько я знаю, когда я печатаю inst.attr, происходит следующее:

  1. Первый attr (чей псевдоним attr_1) найден, и attr теперь экземпляр property класса, который является Дескриптор данных.
    Поэтому он будет переопределять словарь экземпляра, что означает, что вызывается type(inst).__dict__['attr'].__get__(inst, type(inst)).
  2. attr.__get__(inst, type(inst)) вызывает attr.fget(inst), где fget() фактически является attr(self) (функция «raw» attr_1).
  3. И, наконец, attr.fget(inst) возвращает inst.__attr.

  • вот первый вопрос: класс MyClass не имеет атрибут __attr, то, как интерпретировать inst.__attr в шаге 3?

  • Аналогично, в эмулированном сеттере, как Python находит атрибут inst.__attr для назначения value?

  • И тривиальный вопрос: с property является классом, почему бы и нет Property вместо property?

+2

Что такое 'fget'? – thefourtheye

+0

'property' на самом деле считается типом, а не классом (это разные вещи) – RafaelC

+0

@thefourtheye подпись' property' является 'свойством (fget, fset, fdel, doc)', где первые три аргумента являются функциями. Ссылка на документацию в вопросе показывает полную реализацию 'property'. – Zelong

ответ

0

Ваш вопрос напрямую не связан с свойствами и тем, как они работают в качестве дескрипторов данных. Это как раз то, как Python подделывает частные атрибуты, отмеченные как начинающиеся с двух подчеркиваний.

>>> inst.__attr 

Traceback (most recent call last): 
    File "<pyshell#4>", line 1, in <module> 
    inst.__attr 
AttributeError: 'MyClass' object has no attribute '__attr' 

Считают, что вы написали свой код, используя внутреннюю переменную с одним подчеркиванием (обычно конвенции сказать, вы не должны касаться этого, но я не буду применять, делать на свой страх и риск):

>>> class MyClass2(object): 

    def __init__(self, value=None): 
     self.attr = value 

    @property 
    def attr(self): 
     # This acts as a getter? 
     # Let's call the function "attr_1" as alias 
     return self._attr 

    @attr.setter 
    def attr(self, value): 
     # This acts as a setter? 
     # Let's call the function "attr_2" as alias 
     self._attr = value 


>>> inst2 = MyClass2(1) 
>>> inst2._attr 
1 

И вы можете увидеть трюк выглядывал на объект, __dict__

>>> inst2.__dict__ 
{'_attr': 1} 
>>> inst.__dict__ 
{'_MyClass__attr': 1} 

Просто некоторые больше сотрудничать nvince вам, что это не имеет ничего общего со свойствами:

>>> class OtherClass(object): 
    def __init__(self, value): 
     self.__attr = value 
    def get_attr(self): 
     return self.__attr 
    def set_attr(self, value): 
     self.__attr = value 


>>> other_inst = OtherClass(1) 
>>> other_inst.get_attr() 
1 
>>> other_inst.__attr 

Traceback (most recent call last): 
    File "<pyshell#17>", line 1, in <module> 
    other_inst.__attr 
AttributeError: 'OtherClass' object has no attribute '__attr' 
>>> other_inst.__dict__ 
{'_OtherClass__attr': 1} 
>>> other_inst._OtherClass__attr 
1 
>>> other_inst._OtherClass__attr = 24 
>>> other_inst.get_attr() 
24 
>>> inst._MyClass__attr = 23 
>>> inst.attr 
23 

Что касается вашего последнего вопроса, я просто не думаю, что есть такое соглашение в Python, что классы должны начинаться с заглавной буквы. property не является изолированным чехлом (datetime, itemgetter, csv.reader, ...).

+0

Спасибо. Я попробовал вам пример кода и обнаружил, что 'self.attr' и' self._attr' - это точно такой же объект ('inst.attr is inst._attr' возвращает' True'). Почему это происходит? И разве это не сбивает с толку, когда мы определяем две переменные, а одна из которых «защищена» (по крайней мере, она считается «защищенной конвенцией»), но на самом деле они являются одним и тем же объектом? – Zelong

+0

Это не тот же атрибут. но это один и тот же объект. Это то, что вы тестируете при вводе '' inst.attr is inst._attr''. Это похоже на '' a = c; b = c; a is b''. – Cilyan

+1

@Zelong Your второй вопрос возникает только потому, что пример слишком прост. Для этого вам не понадобится свойство. Более сложным, но более точным примером будет класс, который содержит точку в 2D с атрибутами x и y и говорит, что вы хотите, чтобы '' codes'', которое возвращает кортеж, содержащий x и y.Также вы можете определить сеттер, который извлекает x и y из 2-кортежей.Делетер удалит как x, так и y. В соответствии с вашими потребностями x и y могут получить доступ напрямую, или, может быть, вам захочется скрыть их (в Python вы все равно не должны скрываться). – Cilyan