6 ответов:
свойства-это особый вид атрибута. В принципе, когда Python встречает следующий код:
spam = SomeObject() print(spam.eggs)он смотрит вверх
eggsinspam, а затем рассматривает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
вообще говоря, свойство и атрибут-это одно и то же. Однако в Python есть декоратор свойств, который обеспечивает доступ getter/setter к атрибуту (или другим данным).
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
свойство позволяет получать и устанавливать значения, как и обычные атрибуты, но под ним есть метод, который называется переводом его в геттер и сеттер для вас. Это действительно просто удобство, чтобы сократить шаблон вызова геттеров и сеттеров.
допустим, например, у вас был класс, который содержал некоторые координаты x и y для чего-то, что вам нужно. Чтобы установить их, вы можете сделать что-то вроде:
myObj.x = 5 myObj.y = 10это гораздо проще смотрите и думайте о чем пишете:
myObj.setX(5) myObj.setY(10)проблема в том, что если однажды ваш класс изменится так, что вам нужно будет смещать ваши x и y на какое-то значение? Теперь вам нужно будет войти и изменить определение класса и весь код, который его вызывает, что может быть очень трудоемким и подверженным ошибкам. Свойство позволяет использовать первый синтаксис, давая вам гибкость изменения последнего.
в Python можно определить геттеры, сеттеры и удалите методы с помощью функции свойства. Если вы просто хотите свойство read, есть также декоратор @property, который вы можете добавить над своим методом.
я узнал 2 отличия от сайт Бернда Кляйна, вкратце:
1. Собственность-это более удобный способ инкапсуляции данных.
например: если у вас есть общедоступный атрибут длины объекта, позже ваш проект требует, чтобы вы инкапсулировали его, т. е.: измените его на private и предоставьте 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.сеттер>= вам не нужно менять старые коды
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
Comments