Відповіді:
Властивості - особливий вид атрибута. В основному, коли Python стикається з таким кодом:
spam = SomeObject()
print(spam.eggs)
він дивиться eggsна spam, а потім перевіряє , eggsщоб побачити , якщо він має __get__, __set__або __delete__метод - якщо він робить, це властивість. Якщо це властивість, а НЕ тільки повертаючи eggsоб'єкт (як і для будь-якого іншого атрибута) він буде викликати __get__метод (так як ми робимо пошук) і повернення незалежно цей метод повертає.
Більше інформації про модель даних та дескриптори Python .
З властивістю ви маєте повний контроль над його методами getter, setter та Deleter, яких у вас немає (якщо ви не використовуєте застереження) з атрибутом.
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. Односторонній. Якщо користувач класу дізнається про _x, він використовує його на власний ризик.
Взагалі кажучи, властивість та атрибут - це одне і те ж. Однак в Python є декоратор властивостей, який забезпечує доступ геттера / сеттера до атрибуту (або інших даних).
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
Властивість дозволяє отримувати та встановлювати значення на зразок звичайних атрибутів, але під ними є метод, який називається переведенням його в getter та setter. Насправді просто зручно скоротити котлован для виклику геттерів та сетерів.
Скажімо, наприклад, у вас був клас, який містив деякі координати x і y для чогось, що вам потрібно. Щоб встановити їх, ви можете зробити щось на кшталт:
myObj.x = 5
myObj.y = 10
Це набагато простіше подивитися і подумати, ніж написати:
myObj.setX(5)
myObj.setY(10)
Проблема полягає в тому, що, якщо одного дня ваш клас зміниться таким чином, що вам потрібно компенсувати свої значення x і y деяким значенням? Тепер вам потрібно буде зайти і змінити своє визначення класу та весь код, який його викликає, що може зайняти багато часу та схильність до помилок. Властивість дозволяє використовувати колишній синтаксис, надаючи вам гнучкість зміни останнього.
У Python ви можете визначити getters, setters та видалити методи за допомогою функції властивостей. Якщо ви просто хочете властивість прочитати, є також декоратор @property, який ви можете додати вище свого методу.
Я дізнався 2 відмінності від сайту Бернда Кляйна, підсумовуючи:
1. Властивість - це більш зручний спосіб зробити інкапсуляцію даних.
Напр .: Якщо у вас є загальнодоступна довжина атрибуту Object, пізніше ваш проект вимагає від вас інкапсуляції, тобто: змінити його на приватну та надати getter і setter => ви повинні змінити багато кодів, які ви писали раніше:
#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
Якщо ви використовуєте @property та @ lenght.setter => вам не потрібно змінювати ці старі коди
2. Властивість може інкапсулювати кілька атрибутів
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!"
У цьому прикладі, __physic_healthі __mental_healthє приватними і не може бути доступна безпосередньо з поза боку, єдиного способу за межі клас взаємодіє з ними Повсюдно нерухомістюcondition
Також є одна не очевидна відмінність, яку я використовую для кешування або оновлення даних, часто у нас є функція, пов'язана з атрибутом класу. Наприклад, мені потрібно прочитати файл один раз і зберегти вміст, присвоєний атрибуту, щоб значення було кешоване:
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
Вихід:
func running
func value
func value
Ми зверталися до атрибуту двічі, але наша функція була запущена лише один раз. Зміна вищевказаного прикладу на використання властивості призведе до оновлення значення атрибута щоразу, коли ви отримуєте доступ до нього:
class Misc():
@property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Вихід:
func running
func value
func running
func value