'Не удается установить атрибут' с новыми свойствами стиля в Python
Я пытаюсь использовать объявление свойств нового стиля:
class C(object):
def __init__(self):
self._x = 0
@property
def x(self):
print 'getting'
return self._x
@x.setter
def set_x(self, value):
print 'setting'
self._x = value
if __name__ == '__main__':
c = C()
print c.x
c.x = 10
print c.x
и видим следующее в консоли:
pydev debugger: starting
getting
0
File "test.py", line 55, in <module>
c.x = 10
AttributeError: can't set attribute
что я делаю не так? P. S.: В старом стиле декларация нормально работает.
4 ответа:
в документации говорится следующее об использовании декоратора формы
property
:убедитесь, что дополнительные функции имеют то же имя, что и исходное свойство (x в этом случае.)
Я не знаю, почему это так, если вы используете
property
как функция для возврата атрибута методы могут быть вызваны как угодно.поэтому вам нужно изменить свой код следующим образом:
@x.setter def x(self, value): 'setting' self._x = value
метод setter должен иметь то же имя, что и геттер. Не волнуйтесь, декоратор знает, как отличить их друг от друга.
@x.setter def x(self, value): ...
когда вы вызываете @x. setter, @x.getter или @x.deleter, вы создаете новый объект свойства и даете ему имя функции, которую вы украшаете. Так что на самом деле все, что имеет значение, это то, что в последний раз, когда вы используете декоратор @x.*er в определении класса, у него есть имя, которое вы действительно хотите использовать. Но поскольку это приведет к загрязнению пространства имен вашего класса неполными версиями свойства, которое вы хотите использовать, лучше всего использовать одно и то же имя для их очистки.
Если вы не хотите лишний
_x
имя слот, вот сложный маленький трюк, который вы можете сделать:
(проверено с Py34)>>> class C(object): __slots__ = ['x'] # create a member_descriptor def __init__( self ): self.x = 0 # or use this if you don't want to call x_setter: #set_x( self, 0 ) >>> get_x = C.x.__get__ # member_descriptor getter >>> set_x = C.x.__set__ # member_descriptor setter >>> # define custom wrappers: >>> def x_getter( self ): print('getting') return get_x( self ) >>> def x_setter( self, value ): print('setting') set_x( self, value ) >>> C.x = property( x_getter, x_setter ) # replace the member_descriptor >>> c = C() setting >>> print(c.x) getting 0 >>> c.x = 10 setting >>>