Простой Python. Современный стиль программирования (Любанович) - страница 90

>>>> 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

Если вы не укажете сеттер для атрибута, то не сможете устанавливать его значение извне. Это удобно для атрибутов, которые должны быть доступны только для чтения: