Я вообще не понимаю разницы между «свойством» и «атрибутом» и не могу найти отличный ресурс, чтобы кратко описать различия.
155
Свойства - это особый вид атрибута. В основном, когда Python встречает следующий код:
spam = SomeObject()
print(spam.eggs)
он смотрит eggs
на spam
, а затем проверяет , eggs
чтобы увидеть , если он имеет __get__
, __set__
или __delete__
метод - если он делает, это свойство. Если это свойство, а не только возвращая eggs
объект (как и для любого другого атрибута) он будет вызывать __get__
метод (так как мы делаем поиск) и возвращения независимо этот метод возвращает.
Дополнительная информация о модели данных и дескрипторах Python .
С помощью свойства у вас есть полный контроль над его методами получения, установки и удаления, которых у вас нет (если не использовать оговорки) с атрибутом.
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
источник
Свойство позволяет вам получать и устанавливать значения, как обычные атрибуты, но под ним есть вызываемый метод, переводящий его в геттер и сеттер для вас. На самом деле это просто удобство, чтобы сократить шаблон вызова геттеров и сеттеров.
Допустим, например, у вас есть класс, в котором хранятся некоторые координаты x и y для чего-то, что вам нужно. Чтобы установить их, вы можете сделать что-то вроде:
myObj.x = 5 myObj.y = 10
На это гораздо легче смотреть и думать, чем писать:
myObj.setX(5) myObj.setY(10)
Проблема в том, что, если однажды ваш класс изменится так, что вам нужно будет компенсировать x и y на какое-то значение? Теперь вам нужно будет войти и изменить определение вашего класса и весь код, который его вызывает, что может занять много времени и привести к ошибкам. Свойство позволяет вам использовать первый синтаксис, давая вам гибкость при изменении второго.
В Python вы можете определять методы получения, установки и удаления с помощью функции свойства. Если вам просто нужно свойство read, есть также декоратор @property, который вы можете добавить над своим методом.
http://docs.python.org/library/functions.html#property
источник
В итоге я узнал 2 отличия от сайта Бернд Кляйн:
1. Свойство - это более удобный способ инкапсуляции данных.
Например, допустим, у вас есть публичный атрибут
length
. Позже ваш проект требует, чтобы вы инкапсулировали его, то есть изменили его на частный и предоставили геттер и сеттер => вам нужно изменить код, который вы написали ранее:# Old code obj1.length = obj1.length + obj2.length # New code (using private attributes and getter and setter) obj1.set_length(obj1.get_length() + obj2.get_length()) # => this is ugly
Если вы используете
@property
и@length.setter
=>, вам не нужно менять этот старый код.2. Свойство может содержать несколько атрибутов.
class Person: def __init__(self, name, physic_health, mental_health): self.name = name self.__physic_health = physic_health self.__mental_health = mental_health @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
являются частными и не могут быть доступны напрямую извне.источник
Есть также одно неочевидное различие, которое я использую для кеширования или обновления данных, часто у нас есть функция, связанная с атрибутом класса. Например, мне нужно один раз прочитать файл и сохранить контент, присвоенный атрибуту, чтобы значение было кэшировано:
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
Выход:
Мы обращались к атрибуту дважды, но наша функция была запущена только один раз. Изменение приведенного выше примера для использования свойства приведет к обновлению значения атрибута при каждом доступе к нему:
class Misc(): @property def test(self): print 'func running' return 'func value' cl = Misc() print cl.test print cl.test
Выход:
источник