Dlaczego @ foo.setter w Pythonie nie działa dla mnie?
Więc bawię się dekoratorami w Pythonie 2.6 i mam problem z doprowadzeniem ich do pracy. Oto plik mojej klasy:
class testDec:
@property
def x(self):
print 'called getter'
return self._x
@x.setter
def x(self, value):
print 'called setter'
self._x = value
Myślałem, że to oznacza traktowanie x
Jak właściwości, ale wywołanie tych funkcji na get I set. Więc odpaliłem bezczynnie i sprawdziłem:
>>> 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
Oczywiście pierwsze wywołanie działa zgodnie z oczekiwaniami, ponieważ wywołuję getter, i nie ma wartości domyślnej, i to się nie powiedzie. Dobrze, rozumiem. Jednak wywołanie przypisania t.x = 5
wydaje się tworzyć nowe property x
, a teraz getter nie działa!
4 answers
Wydaje się, że używasz klasycznych klas starego stylu w Pythonie 2. Aby Właściwości działały poprawnie, musisz użyć klas nowego stylu (w Pythonie 2 musisz dziedziczyć z object
). Po prostu zadeklaruj swoją klasę jako 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
Działa:
>>> 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
>>>
Innym szczegółem, który może powodować problemy, jest to, że obie metody wymagają tej samej nazwy, aby właściwość działała. jeśli zdefiniujesz seter z inną nazwą, jak ta, to nie praca:
@x.setter
def x_setter(self, value):
...
I jeszcze jedna rzecz, która nie jest łatwa do zauważenia na początku, to kolejność: getter musi być zdefiniowany jako pierwszy. Jeśli najpierw zdefiniujesz setter, otrzymasz błąd name 'x' is not defined
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-06 17:55:32
Tylko uwaga dla innych ludzi, którzy natkną się tutaj szukając tego wyjątku: obie funkcje muszą mieć tę samą nazwę. Nazwanie metod w następujący sposób spowoduje wyjątek:
@property
def x(self): pass
@x.setter
def x_setter(self, value): pass
Zamiast tego nadaj obu metodom tę samą nazwę
@property
def x(self): pass
@x.setter
def x(self, value): pass
Ważne jest również, aby pamiętać, że kolejność deklaracji ma znaczenie. Getter musi być zdefiniowany przed setterem w pliku, w przeciwnym razie otrzymasz NameError: name 'x' is not defined
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-18 20:26:53
Musisz użyć klas nowego stylu, które robisz, wyprowadzając klasę z obiektu:
class testDec(object):
....
To powinno zadziałać.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-28 14:43:22
W przypadku, gdyby ktoś przyszedł tutaj z google, oprócz powyższych odpowiedzi chciałbym dodać, że wymaga to uważnej uwagi przy wywoływaniu setera z metody __init__
twojej klasy opartej na tej odpowiedzi
Konkretnie:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:16