>>>> c.diameter = 20
>Traceback (most recent call last):
>··File "", line 1, in
>AttributeError: can't set attribute
У использования свойств вместо непосредственного доступа к атрибутам имеется еще одно преимущество: если вы измените определение атрибута, вам нужно будет поправить только код внутри определения класса вместо того, чтобы править все вызовы.
Искажение имен для безопасности
В примере с классом 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'
Обратите внимание на то, что на экране не появилась надпись inside the getter. Хотя эта защита не идеальна, искаженное имя отказывается случайно или намеренно получать доступ к атрибуту.
Одни данные (атрибуты) и функции (методы) являются частью самого класса, а другие — частью объектов, которые созданы на его основе.
Когда вы видите начальный аргумент self в методах внутри определения класса, этот метод является методом экземпляра. Такие методы вы обычно пишете при создании собственного класса. Первый параметр метода экземпляра — это self, и Python передает объект методу, когда вы его вызываете.
В противоположность ему метод класса влияет на весь класс целиком. Любое изменение, которое происходит с классом, влияет на все его объекты. Внутри определения класса декоратор @classmethod показывает, что следующая функция является методом класса. Первым параметром метода также является сам класс. Согласно традиции этот параметр называется cls, поскольку слово class является зарезервированным и не может быть использовано здесь. Определим метод класса для А, который будет подсчитывать количество созданных объектов: