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

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

>>> c.diameter = 20

Traceback (most recent call last):

··File "", line 1, in

AttributeError: can't set attribute

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

<p>Искажение имен для безопасности</p>

В примере с классом Duck из предыдущего раздела мы вызывали наш (не полностью) скрытый атрибут hidden_name. Python предлагает соглашения по именованию для атрибутов, которые не должны быть видимы за пределами определения их классов: имена начинаются с двух нижних подчеркиваний (__).

Переименуем атрибут hidden_name в __name, как показано здесь:

>>> class Duck():

…·····def __init__(self, input_name):

…·········self.__name = input_name

…·····@property

…·····def name(self):

…·········print('inside the getter')

…·········return self.__name

…·····@name.setter

…·····def name(self, input_name):

…·········print('inside the setter')

…·········self.__name = input_name

Теперь проверим, работает ли все как полагается:

>>> fowl = Duck('Howard')

>>> fowl.name

inside the getter

'Howard'

>>> fowl.name = 'Donald'

inside the setter

>>> fowl.name

inside the getter

'Donald'

Выглядит хорошо. И вы не можете получить доступ к атрибуту __name:

>>> fowl.__name

Traceback (most recent call last):

··File "", line 1, in

AttributeError: 'Duck' object has no attribute '__name'

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

>>> fowl._Duck__name

'Donald'

Перейти на страницу:

Все книги серии Бестселлеры O'Reilly

Похожие книги