Мы могли бы сделать это, но в таком случае потеряли бы возможность применять наследование. Мы использовали метод super(), чтобы создать объект, который работает примерно так же, как и объект класса Person. Есть и другое преимущество: если определение класса Person в будущем изменится, с помощью метода super() мы сможем гарантировать, что атрибуты и методы, которые класс EmailPerson наследует от класса Person, отреагируют на изменения.

Используйте метод super(), когда потомок делает что-то самостоятельно, но ему все еще нужно что-то от предка (как и в реальной жизни).

<p>В защиту self</p>

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!

Однако нет причин использовать такой более длинный стиль.

<p>Получаем и устанавливаем значение атрибутов с помощью свойств</p>

Отдельные объектно-ориентированные языки поддерживают закрытые атрибуты объектов, к которым нельзя получить доступ непосредственно; программистам зачастую приходится писать геттеры и сеттеры, чтобы считать и записать значения таких атрибутов.

В 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(), который возвращает его:

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

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

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

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