Свойства (@property) объектов

Использование декоратора @property

@property декоратор может быть использован для определения методов в классе , которые действуют как атрибуты. Одним из примеров, где это может быть полезно, является предоставление информации, которая может потребовать первоначального (дорогостоящего) поиска и простого поиска после этого.

Учитывая некоторый модуль foobar.py :

class Foo(object):
  def __init__(self):
    self.__bar = None
  @property
  def bar(self):
    if self.__bar is None:
      self.__bar = some_expensive_lookup_operation()
    return self.__bar 

затем

from foobar import Foo
foo = Foo()
print(foo.bar)  # Это займет некоторое время, так как
				# bar после инициализации имеет значение None.

# 42
print(foo.bar)  # Это намного быстрее, так как bar
				# теперь имеет значение
# 42 

Использование декоратора @property для свойств чтения-записи

Если вы хотите использовать @property для реализации пользовательского поведения для установки и получения, использовать этот шаблон:

class Cash(object):
  def __init__(self, value):
    self.value = value
  @property
  def formatted(self):
    return '${:.2f}'.format(self.value)
  @formatted.setter
  def formatted(self, new):
    self.value = float(new[1:])

Чтобы использовать это:

wallet = Cash(2.50)
print(wallet.formatted)
# $2.50

print(wallet.value)
# 2.5

wallet.formatted = '$123.45'
print(wallet.formatted)
# $123.45

print(wallet.value)
# 123.45

Переопределение только метода получения, установки или удаления объекта свойства

При наследовании от класса со свойством, вы можете предоставить новую реализацию одного или несколько свойства getter , setter или deleter функций, с помощью ссылки на объекте собственности на родительском классе:

class BaseClass(object):
  @property
  def foo(self):
    return # some_calculated_value()    
  @foo.setter
  def foo(self, value):
    return # do_something_with_value(value)

class DerivedClass(BaseClass):
  @BaseClass.foo.setter
  def foo(self, value):
    return # do_something_different_with_value(value)

Вы также можете добавить установщик или удалитель, если раньше его не было в базовом классе.

Использование свойств без декораторов

Хотя использование синтаксиса декоратора (с @) удобно, оно также немного скрыто. Вы можете использовать свойства напрямую, без декораторов. Следующий пример Python 3.x показывает это:

class A:
    p = 1234
    def getX (self):
        return self._x

    def setX (self, value):
        self._x = value

    def getY (self):
        return self._y

    def setY (self, value):
        self._y = 1000 + value    # Странно, но можно

    def getY2 (self):
        return self._y

    def setY2 (self, value):
        self._y = value

    def getT    (self):
        return self._t

    def setT (self, value):
        self._t = value

    def getU (self):
        return self._u + 10000

    def setU (self, value):
        self._u = value - 5000

    x, y, y2 = property (getX, setX), property (getY, setY), property (getY2, setY2)
    t = property (getT, setT)
    u = property (getU, setU)

A.q = 5678

class B:
    def getZ (self):
        return self.z_

    def setZ (self, value):
        self.z_ = value

    z = property (getZ, setZ)

class C:
    def __init__ (self):
        self.offset = 1234

    def getW (self):
        return self.w_ + self.offset

    def setW (self, value):
        self.w_ = value - self.offset

    w = property (getW, setW)

a1 = A()
a2 = A()

a1.y2 = 1000
a2.y2 = 2000

a1.x = 5
a1.y = 6

a2.x = 7
a2.y = 8

a1.t = 77
a1.u = 88

print(a1.x, a1.y, a1.y2)
# 5 6 1000

print(a2.x, a2.y, a2.y2)
# 7 8 2000

print(a1.p, a2.p, a1.q, a2.q)
# 1234 1234 5678 5678

print(a1.t, a1.u)
# 77 88

b = B()
c = C()

b.z = 100100
c.z = 200200
c.w = 300300

print(a1.x, b.z, c.z, c.w)
# 5 100100 200200 300300

c.w = 400400
c.z = 500500
b.z = 600600

print(a1.x, b.z, c.z, c.w)
# 5 600600 500500 400400