Это занятие является продолжением предыдущего, где мы
рассматривали приватные атрибуты, сеттеры и геттеры, а также контроль за их
изменением при помощи перегрузки некоторых базовых методов. Однако,
пользоваться на практике напрямую геттерами и сеттерами бывает не всегда
удобно. Большего изящества кода можно добиться, используя так называемые
объекты-свойства (property). Например, мы хотим создать в классе Point свойство
coordX
которому можно
было бы присваивать и считывать значения подобно обычной переменной:
pt.coordX = 100 # запись значения
x = pt.coordX # чтение значения
но с
дополнительной проверкой корректности записи и считывания данных. Для этого
создадим внутри класса геттер и сеттер, на основе которых будет работать это
свойство. Пусть они будут очень простыми:
def __getCoordX(self):
print("вызов __getCoordX")
return self.__x
def __setCoordX(self, x):
print("вызов __setCoordX")
self.__x = x
То есть, при
вызове геттера мы возвращаем значение приватного свойства__x, а при вызове
сеттера – заносим новое значение в этот атрибут. На основе этих приватных
методов создаем свойство через специальный класс property:
coordX = property(__getCoordX, __setCoordX)
Все, наше
свойство готово и далее можем работать с ним, используя синтаксис обычной
переменной:
pt = Point()
print( pt.coordX )
pt.coordX = 100
print( pt.coordX )
Видите, это
намного удобнее, чем вызывать отдельно сеттеры и геттеры.
Теперь уберем из
геттера и сеттера функцию print и добавим
проверку на корректность передаваемых данных:
def __getCoordX(self):
return self.__x
def __setCoordX(self, x):
if Point.__checkValue(x):
self.__x = x
else:
raise ValueError("Неверный формат данных")
Теперь, если
попытаться передать не числовое значение:
то возникнет
исключение ValueError.
У свойства может
быть еще один метод, вызываемый при его удалении:
def __delCoordX(self):
print("Удаление свойства")
del self.__x
Он указывается
третьим параметром при вызове класса property, а четвертым
можно указать описание свойства:
coordX = property(__getCoordX, __setCoordX, __delCoordX, "Работа с X")
Если теперь
выполнить удаление свойства:
то увидим
сообщение «Удаление свойства» и дальнейшая попытка к его обращению:
приведет к
ошибке, т.к. приватного свойства __x уже не существует. Вот так
работают и создаются свойства в Python. И давайте здесь же я вам покажу
еще один способ объявления свойств через декораторы (если вы не знаете что
такое декоратор, то смотрите урок по этой теме – ссылка
под этим видео).
Перед геттером
мы укажем декоратор
И название
метода должно совпадать с названием свойства:
Далее, у сеттера
указываем декоратор с то же имя метода:
@coordX.setter
def coordX(self, x):
То есть, пишем
имя нашего свойства и через точку зарезервированное имя setter. Ну а перед
делитером декоратор
@coordX.deleter
def coordX(self):
Все, теперь мы
абсолютно также можем работать со свойством coordX:
pt = Point()
print( pt.coordX )
pt.coordX = 100
print( pt.coordX )
del pt.coordX
Хорошо, свойство
coordX у нас есть. Но
нам нужно создать еще одно – coordY. Как вы понимаете, это,
фактически, приведет к дублированию кода для coordX, что не есть
хорошо, так как нарушает принцип программирования
DRY
(Don’t Repeat Yourself) – не повторяйся!
И здесь нам на
помощь приходит другой механизм Python – дескрипторы, о котором речь пойдет на следующем занятии.