Python критикуют за то, что, помимо применения пробелов, необходимо включать self в качестве первого аргумента методов экземпляра класса (методов, которые вы видели в предыдущем примере). Python использует аргумент self, чтобы найти атрибуты и методы правильного объекта. Например, я покажу, как вы можете вызвать метод объекта и что Python сделает при этом за кулисами.
Помните класс Car из предыдущих примеров? Снова вызовем метод exclaim():
>>>> car = Car()
>>>> car.exclaim()
>I'm a Car!
Вот что происходит за кулисами Python.
• Выполняется поиск класса (Car) объекта car.
• Объект car передается методу exclaim() класса Car как параметр self.
Ради забавы вы и сами можете запустить пример таким образом, и он сработает точно так же, как и нормальный синтаксис (car.exclaim()):
>>>> Car.exclaim(car)
>I'm a Car!
Однако нет причин использовать такой более длинный стиль.
Получаем и устанавливаем значение атрибутов с помощью свойств
Отдельные объектно-ориентированные языки поддерживают закрытые атрибуты объектов, к которым нельзя получить доступ непосредственно; программистам зачастую приходится писать геттеры и сеттеры, чтобы считать и записать значения таких атрибутов.
В Python геттеры и сеттеры не нужны, поскольку все атрибуты и методы являются открытыми, а от вас ожидается примерное поведение. Если прямой доступ к атрибутам заставляет вас нервничать, вы, конечно, можете написать геттеры и сеттеры. Но сделайте это более характерным для Python способом — используйте свойства.
В этом примере мы определим класс Duck, имеющий один атрибут hidden_name. (В следующем разделе я покажу вам более удачный способ именовать атрибуты, которые вы хотите оставить закрытыми.) Мы не хотим, чтобы люди обращались к атрибуту напрямую, поэтому определим два метода: геттер (get_name()) и сеттер (set_name()). Я добавил выражение print() в каждый из них, чтобы показать момент его вызова. Наконец, мы определим эти методы как свойства атрибута name:
>>>> class Duck():
>…·····def __init__(self, input_name):
>…·········self.hidden_name = input_name
>…·····def get_name(self):
>…·········print('inside the getter')
>…·········return self.hidden_name
>…·····def set_name(self, input_name):
>…·········print('inside the setter')
>…·········self.hidden_name = input_name
>…·····name = property(get_name, set_name)
Новые методы действуют как обычные геттеры и сеттеры до последней строки, где они указываются как свойства атрибута name. Первый аргумент функции property() — это геттер, а второй — это сеттер. Теперь, когда вы обращаетесь к атрибуту name любого объекта Duck, вызывается метод get_name(), который возвращает его: