@property
Zamienia metodę w atrybut: wartość jest wyliczana przy odczycie, a opcjonalny setter kontroluje zapis.
Przykład
#class Student:
def __init__(self, name, points=0):
self.name = name
self.points = points
@property
def level(self):
return self.points // 100 + 1
ania = Student("Ania", 250)
print(ania.level)
ania.points += 100
print(ania.level)
try:
ania.level = 10
except AttributeError as error:
print(error)Definicja i zastosowanie
#Dekorator @property sprawia, że metodę odczytujesz jak zwykły atrybut, bez nawiasów: student.level zamiast student.level(). Wartość jest wyliczana przy każdym odczycie, więc zawsze zgadza się z aktualnym stanem obiektu, np. poziom liczony z punktów.
Właściwość bez settera jest tylko do odczytu, a próba przypisania zgłasza AttributeError. Żeby pozwolić na zapis z kontrolą, dopisz drugą metodę o tej samej nazwie z dekoratorem @nazwa.setter. Setter może sprawdzić albo przekształcić nową wartość, zanim zapisze ją w atrybucie z podkreślnikiem, np. self._points.
Właściwości pozwalają zacząć od zwykłego atrybutu i dodać walidację później, bez zmieniania kodu, który z klasy korzysta. Dlatego w Pythonie nie pisze się na zapas metod get_points() i set_points(), jak w Javie. Wynik kosztownych obliczeń, który się nie zmienia, zapamięta dekorator functools.cached_property.
Składnia
#class Nazwa:
@property
def atrybut(self):
return self._atrybut
@atrybut.setter
def atrybut(self, wartosc):
self._atrybut = wartoscElementy właściwości
#@property
obiekt.x
Getter, czyli metoda uruchamiana przy odczycie. Jej wynik staje się wartością atrybutu.@x.setter
obiekt.x = v
Setter, czyli metoda uruchamiana przy przypisaniu. Dostaje nową wartość jako parametr. Bez niej atrybut jest tylko do odczytu.@x.deleter
del obiekt.x
Metoda uruchamiana przy usuwaniu atrybutu. Potrzebna rzadko.
Więcej przykładów
#class Student:
def __init__(self, name, points=0):
self.name = name
self.points = points
@property
def points(self):
return self._points
@points.setter
def points(self, value):
if value < 0:
raise ValueError("Punkty nie mogą być ujemne")
self._points = value
kuba = Student("Kuba", 40)
kuba.points += 25
print(kuba.points)
try:
kuba.points = -5
except ValueError as error:
print(error)
print(kuba.points)Przypisanie self.points = points w __init__ też przechodzi przez setter, więc obiektu z ujemną liczbą punktów nie da się nawet utworzyć.
from functools import cached_property
class Course:
def __init__(self, title, lessons):
self.title = title
self.lessons = lessons
@cached_property
def total_minutes(self):
print("Liczę czas trwania...")
return sum(self.lessons)
python = Course("Python", [15, 20, 25])
print(python.total_minutes)
print(python.total_minutes)Dobre praktyki
#- Właściwość powinna działać szybko i niczego nie zmieniać. Czytelnik kodu zakłada, że odczyt atrybutu to prosta, bezpieczna operacja.
- Wartość przechowuj w atrybucie o innej nazwie, zwykle z podkreślnikiem (
self._points). Zapisself.points = valuewewnątrz settera wywoływałby ten sam setter w nieskończoność. - Nie twórz właściwości na zapas. Zacznij od zwykłego atrybutu i zamień go na
@property, gdy pojawi się potrzeba walidacji albo wyliczania wartości.
Powiązane hasła
#- DekoratoryFunkcje, które opakowują inne funkcje i dodają im zachowanie, np. logowanie lub sprawdzanie uprawnień. Zapis @nazwa.
- classDefiniuje klasę: szablon obiektów łączący dane i funkcje, które na nich działają.
- selfPierwszy parametr metody: obiekt, na którym metodę wywołano. Daje dostęp do jego atrybutów i innych metod.
- @dataclassDekorator, który na podstawie pól z adnotacjami typów generuje __init__, __repr__ i __eq__ klasy przechowującej dane.
- functoolsNarzędzia do pracy z funkcjami: zapamiętywanie wyników (lru_cache), częściowe wywołania (partial) i zwijanie kolekcji (reduce).
Widzisz błąd albo brakuje przykładu? Napisz do nas.