Odpowiedzi:
Właściwości to specjalny rodzaj atrybutów. Zasadniczo, gdy Python napotka następujący kod:
spam = SomeObject()
print(spam.eggs)
wygląda się eggsw spam, a następnie sprawdza eggs, czy to ma __get__, __set__albo __delete__metodę - jeśli to robi, to jest nieruchomość. Jeśli jest to właściwość, zamiast po prostu zwracać eggsobiekt (tak jak w przypadku każdego innego atrybutu), wywoła __get__metodę (ponieważ szukaliśmy) i zwróci cokolwiek zwraca ta metoda.
Więcej informacji o modelu danych i deskryptorach Pythona .
Dzięki właściwości masz pełną kontrolę nad jej metodami pobierającymi, ustawiającymi i usuwającymi, których nie masz (jeśli nie używasz zastrzeżeń) z atrybutem.
class A(object):
_x = 0
'''A._x is an attribute'''
@property
def x(self):
'''
A.x is a property
This is the getter method
'''
return self._x
@x.setter
def x(self, value):
"""
This is the setter method
where I can check it's not assigned a value < 0
"""
if value < 0:
raise ValueError("Must be >= 0")
self._x = value
>>> a = A()
>>> a._x = -1
>>> a.x = -1
Traceback (most recent call last):
File "ex.py", line 15, in <module>
a.x = -1
File "ex.py", line 9, in x
raise ValueError("Must be >= 0")
ValueError: Must be >= 0
x. Jednokierunkowa. Jeśli użytkownik klasy dowie się o _x, użyje go na własne ryzyko.
Ogólnie rzecz biorąc, właściwość i atrybut to to samo. Jednak w Pythonie istnieje dekorator właściwości, który zapewnia pobierający / ustawiający dostęp do atrybutu (lub innych danych).
class MyObject(object):
# This is a normal attribute
foo = 1
@property
def bar(self):
return self.foo
@bar.setter
def bar(self, value):
self.foo = value
obj = MyObject()
assert obj.foo == 1
assert obj.bar == obj.foo
obj.bar = 2
assert obj.foo == 2
assert obj.bar == obj.foo
Ta właściwość pozwala na pobieranie i ustawianie wartości tak, jak w przypadku zwykłych atrybutów, ale pod spodem znajduje się metoda nazywana tłumaczeniem jej na metodę pobierającą i ustawiającą. To naprawdę tylko wygoda, aby ograniczyć schemat wywoływania metod pobierających i ustawiających.
Powiedzmy na przykład, że masz klasę, która zawierała jakieś współrzędne xiy dla czegoś, czego potrzebujesz. Aby je ustawić, możesz zrobić coś takiego:
myObj.x = 5
myObj.y = 10
O wiele łatwiej jest na to spojrzeć i pomyśleć niż napisać:
myObj.setX(5)
myObj.setY(10)
Problem w tym, co się stanie, jeśli pewnego dnia twoja klasa zmieni się tak, że będziesz musiał zrównoważyć swoje x i y o jakąś wartość? Teraz musisz wejść i zmienić definicję klasy i cały kod, który ją wywołuje, co może być naprawdę czasochłonne i podatne na błędy. Właściwość pozwala na użycie poprzedniej składni, dając jednocześnie elastyczność zmiany drugiej.
W Pythonie można definiować metody pobierające, ustawiające i usuwające za pomocą funkcji właściwości. Jeśli potrzebujesz tylko właściwości read, istnieje również dekorator @property, który możesz dodać nad metodą.
Dowiedziałem się 2 różnic ze strony Bernda Kleina, podsumowując:
1. Właściwość jest wygodniejszym sposobem enkapsulacji danych.
np. jeśli masz atrybut public długość Object, później projekt wymaga, abyś go hermetyzował, tj .: zmień go na prywatny i podaj getter i setter => musisz zmienić wiele kodów, które napisałeś wcześniej:
#Old codes
obj1.length=obj1.length+obj2.length
#New codes(Using private attibutes and getter and setter)
obj1.set_lenght(obj1.get_length()+obj2.get_length()) #=> this is ugly
Jeśli używasz @property i @ lenght.setter =>, nie musisz zmieniać tych starych kodów
2. Właściwość może zawierać wiele atrybutów
class Person:
def __init__(self, name, physic_health, mental_health):
self.name=name
self.__physic_health=physic_health #physic_health is real value in range [0, 5.0]
self.__mental_health=mental_health #mental_health is real value in range [0, 5.0]
@property
def condition(self):
health=self.__physic_health+self.__mental_health
if(health<5.0):
return "I feel bad!"
elif health<8.0:
return "I am ok!"
else:
return "Great!"
W tym przykładzie __physic_healthi __mental_healthsą prywatne i nie można uzyskać do nich dostępu bezpośrednio z zewnątrz, jedynym sposobem interakcji z nimi poza klasą jest poprzez właściwośćcondition
Jest też jedna nieoczywista różnica, której używam do buforowania lub odświeżania danych, często mamy funkcję połączoną z atrybutem klasy. Na przykład muszę raz przeczytać plik i zachować zawartość przypisaną do atrybutu, aby wartość była buforowana:
class Misc():
def __init__(self):
self.test = self.test_func()
def test_func(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Wynik:
func running
func value
func value
Uzyskaliśmy dostęp do atrybutu dwukrotnie, ale nasza funkcja została uruchomiona tylko raz. Zmiana powyższego przykładu na użycie właściwości spowoduje odświeżenie wartości atrybutu przy każdym dostępie do niego:
class Misc():
@property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Wynik:
func running
func value
func running
func value