W Pythonie dekorator @property umożliwia tworzenie atrybutów "wirtualnych" — metod, które wyglądają i działają jak zwykłe pola, ale wykonują logikę getterów, setterów lub deleterów. Jest to wygodne dla tworzenia właściwości obliczeniowych lub kontrolowania dostępu do danych.
Przykład:
class Rectangle: def __init__(self, width, height): self._width = width self._height = height @property def area(self): return self._width * self._height @property def width(self): return self._width @width.setter def width(self, value): if value <= 0: raise ValueError('Width must be positive') self._width = value r = Rectangle(3, 4) print(r.area) # 12 (wywoływane jak właściwość, nie funkcja) r.width = 10 # setter wywołany automatycznie
Czy można używać tylko jednego @property (metody get), nie definiując settera? Co się stanie, jeśli spróbujesz zmienić taki atrybut?
Odpowiedź: Można zdefiniować tylko getter @property bez settera (i deletera). Taki atrybut będzie tylko do odczytu, a próba przypisania spowoduje AttributeError.
class C: @property def x(self): return 42 c = C() c.x = 99 # AttributeError: can't set attribute
Historia
Próbowano zserializować obiekt za pomocą standardowej biblioteki, używając vars(obj), aby uzyskać słownik atrybutów. Okazało się, że metody property nie wchodzą w wynik __dict__, ich wartości nie były serializowane, co prowadziło do wycieku danych.
Historia
W projekcie zapomniano dodać settera dla property, w efekcie próba zmiany wartości obliczanego pola prowadziła do błędu w czasie wykonywania, chociaż z logiką architektury to było oczekiwane.
Historia
W działającym kodzie obliczenie wartości właściwości umożliwiało ciężkie lub niebezpieczne operacje, które niespodziewanie były wywoływane przy każdym dostępie do właściwości. To obniżyło wydajność i prowadziło do blokujących wywołań w kodzie wielowątkowym.