>>>> fowl = Duck('Howard')
>>>> fowl.name
>inside the getter
>'Howard'
Вы все еще можете вызвать метод get_name() непосредственно, как обычный геттер:
>>>> fowl.get_name()
>inside the getter
>'Howard'
Когда вы присваиваете значение атрибуту name, вызывается метод set_name():
>>>> fowl.name = 'Daffy'
>inside the setter
>>>> fowl.name
>inside the getter
>'Daffy'
Метод set_name() вы также можете вызвать непосредственно:
>>>> fowl.set_name('Daffy')
>inside the setter
>>>> fowl.name
>inside the getter
>'Daffy'
Еще один способ определить свойства — это декораторы. В следующем примере мы определим два разных метода с именем name(), предшествовать которым будут разные декораторы:
• @property, который размещается перед геттером;
• @name.setter, который размещается перед сеттером.
В коде они выглядят так:
>>>> class Duck():
>…·····def __init__(self, input_name):
>…·········self.hidden_name = input_name
>…·····@property
>…·····def name(self):
>…·········print('inside the getter')
>…·········return self.hidden_name
>…·····@name.setter
>…·····def name(self, input_name):
>…·········print('inside the setter')
>…·········self.hidden_name = input_name
Вы все еще можете получать доступ к атрибуту name, но в этом случае не существует видимых методов get_name() или set_name():
>>>> fowl = Duck('Howard')
>>>> fowl.name
>inside the getter
>'Howard'
>>>> fowl.name = 'Donald'
>inside the setter
>>>> fowl.name
>inside the getter
>'Donald'
Если кто-то догадается, что мы называли наш атрибут hidden_name, он сможет считать и записать его непосредственно с помощью конструкции fowl.hidden_name. В следующем разделе вы увидите особый способ именования закрытых атрибутов в Python.
В обоих предыдущих примерах мы использовали свойство name, чтобы обратиться к отдельному атрибуту (в нашем случае hidden_name), который хранится внутри объекта. Свойство может ссылаться и на вычисляемое значение. Определим класс Circle, который имеет атрибут radius и вычисляемое свойство diameter:
>>>> class Circle():
>…·····def __init__(self, radius):
>…·········self.radius = radius
>…·····@property
>…·····def diameter(self):
>…·········return 2 * self.radius
>…
Мы создаем объект класса Circle, задав значение его атрибута radius:
>>>> c = Circle(5)
>>>> c.radius
>5
Мы можем обратиться к свойству diameter точно так же, как к атрибуту вроде radius:
>>>> c.diameter
>10
А вот и самое интересное — мы можем изменить значение атрибута radius в любой момент и свойство diameter будет рассчитано на основе текущего значения атрибута radius:
>>>> c.radius = 7
>>>> c.diameter
>14
Если вы не укажете сеттер для атрибута, то не сможете устанавливать его значение извне. Это удобно для атрибутов, которые должны быть доступны только для чтения: