Почему @foo.setter в Python у меня не работает?
-
11-09-2019 - |
Вопрос
Итак, я играю с декораторами в Python 2.6, и у меня возникают некоторые проблемы с тем, чтобы заставить их работать.Вот мой файл класса:
class testDec:
@property
def x(self):
print 'called getter'
return self._x
@x.setter
def x(self, value):
print 'called setter'
self._x = value
То, что, как я думал, это означало, - это лечить x
как свойство, но вызывайте эти функции в get и set.Итак, я запустил двигатель на холостом ходу и проверил его:
>>> from testDec import testDec
from testDec import testDec
>>> t = testDec()
t = testDec()
>>> t.x
t.x
called getter
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "testDec.py", line 18, in x
return self._x
AttributeError: testDec instance has no attribute '_x'
>>> t.x = 5
t.x = 5
>>> t.x
t.x
5
Очевидно, что первый вызов работает так, как ожидалось, поскольку я вызываю средство получения, а значения по умолчанию нет, и происходит сбой.Ладно, хорошо, я понимаю.Однако вызов для назначения t.x = 5
кажется, создает новое свойство x
, и теперь геттер не работает!
Что я упускаю из виду?
Решение
Вы, кажется, используете классические занятия в старом стиле в python 2.Для того, чтобы свойства для корректной работы вам необходимо использовать занятия в новом стиле вместо этого (в python 2 вы должны наследовать от object
).Просто объявите свой класс как MyClass(object)
:
class testDec(object):
@property
def x(self):
print 'called getter'
return self._x
@x.setter
def x(self, value):
print 'called setter'
self._x = value
Это работает:
>>> k = testDec()
>>> k.x
called getter
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/devel/class_test.py", line 6, in x
return self._x
AttributeError: 'testDec' object has no attribute '_x'
>>> k.x = 5
called setter
>>> k.x
called getter
5
>>>
Еще одна деталь, которая может вызвать проблемы, заключается в том, что для работы свойства обоим методам требуется одно и то же имя. Если вы определите сеттер с другим именем, подобным этому, это не сработает:
@x.setter
def x_setter(self, value):
...
И еще одна вещь, которую поначалу не совсем легко заметить, - это порядок:Добытчик сначала должно быть определено.Если вы сначала определите установщик, вы получите name 'x' is not defined
ошибка.
Другие советы
Просто примечание для других людей, которые натыкаются здесь в поисках этого исключения:обе функции должны иметь одно и то же имя.Присвоение имен методам следующим образом приведет к исключению:
@property
def x(self): pass
@x.setter
def x_setter(self, value): pass
Вместо этого дайте обоим методам одно и то же имя
@property
def x(self): pass
@x.setter
def x(self, value): pass
Также важно отметить, что порядок представления декларации имеет значение.Параметр getter должен быть определен перед параметром setter в файле, иначе вы получите NameError: name 'x' is not defined
Вам нужно использовать классы нового стиля, которые вы делаете, производя свой класс из object:
class testDec(object):
....
Тогда это должно сработать.
На случай, если кто-нибудь придет сюда из Google, в дополнение к приведенным выше ответам я хотел бы добавить, что это требует пристального внимания при вызове установщика из __init__
метод вашего класса, основанный на этот ответ
В частности:
class testDec(object):
def __init__(self, value):
print 'We are in __init__'
self.x = value # Will call the setter. Note just x here
#self._x = value # Will not call the setter
@property
def x(self):
print 'called getter'
return self._x # Note the _x here
@x.setter
def x(self, value):
print 'called setter'
self._x = value # Note the _x here
t = testDec(17)
print t.x
Output:
We are in __init__
called setter
called getter
17