Добавим атрибут, специфический для электромобилей (например, мощность аккумулятора), и метод для вывода информации об этом атрибуте:

class Car():

...

class ElectricCar(Car):

"""Представляет аспекты машины, специфические для электромобилей."""

def __init__(self, make, model, year):

. . . ."""

. . . .Инициализирует атрибуты класса-родителя.

. . . .Затем инициализирует атрибуты, специфические для электромобиля.

. . . ."""

super().__init__(make, model, year)

(1) . . . .self.battery_size = 70

. . . .

(2) . .def describe_battery(self):

. . . ."""Выводит информацию о мощности аккумулятора."""

. . . .print("This car has a " + str(self.battery_size) + "-kWh battery.")

my_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())

my_tesla.describe_battery()

В точке (1) добавляется новый атрибут self.battery_size, которому присваивается исходное значение — скажем, 70. Этот атрибут будет присутствовать во всех экземплярах, созданных на основе класса ElectricCar (но не во всяком экземпляре Car). Также добавляется метод с именем describe_battery(), который выводит информацию об аккумуляторе в точке (2). При вызове этого метода выводится описание, которое явно относится только к электромобилям:

2016 Tesla Model S

This car has a 70-kWh battery.

Возможности специализации класса ElectricCar беспредельны. Вы можете добавить сколько угодно атрибутов и методов, чтобы моделировать электромобиль с любой нужной точностью. Атрибуты или методы, которые могут принадлежать любой машине (а не только электромобилю), должны добавляться в класс Car вместо ElectricCar. Тогда эта информация будет доступна всем пользователям класса Car, а класс ElectricCar будет содержать только код информации и поведения, специфических для электромобилей.

<p>Переопределение методов класса-родителя</p>

Любой метод родительского класса, который в моделируемой ситуации делает не то, что нужно, можно переопределить. Для этого в классе-потомке определяется метод с тем же именем, что и у метода класса-родителя. Python игнорирует метод родителя и обращает внимание только на метод, определенный в потомке.

Допустим, в классе Car имеется метод fill_gas_tank(). Для электромобилей заправка бензином бессмысленна, поэтому этот метод логично переопределить. Например, это можно сделать так:

def ElectricCar(Car):

...

. .def fill_gas_tank():

. . . ."""У электромобилей нет бензобака."""

. . . .print("This car doesn't need a gas tank!")

И если кто-то попытается вызвать метод fill_gas_tank() для электромобиля, Python игнорирует метод fill_gas_tank() класса Car и выполнит вместо него этот код. С применением наследования потомок сохраняет те аспекты родителя, которые вам нужны, и переопределяет все ненужное.

<p>Экземпляры как атрибуты</p>

При моделировании явлений реального мира в программах классы нередко дополняются все большим количеством подробностей. Списки атрибутов и методов растут, и через какое-то время файлы становятся длинными и громоздкими. В такой ситуации часть одного класса нередко можно записать в виде отдельного класса. Большой код разбивается на меньшие классы, которые работают во взаимодействии друг с другом.

Например, при дальнейшей доработке класса ElectricCar может оказаться, что в нем появилось слишком много атрибутов и методов, относящихся к аккумулятору. В таком случае можно остановиться и переместить все эти атрибуты и методы в отдельный класс с именем Battery. Затем экземпляр Battery становится атрибутом класса ElectricCar:

class Car():

...

(1) class Battery():

. ."""Простая модель аккумулятора электромобиля."""

(2) . .def __init__(self, battery_size=70):

. . . ."""Инициализирует атрибуты аккумулятора."""

. . . .self.battery_size = battery_size

(3) . .def describe_battery(self):

. . . ."""Выводит информацию о мощности аккумулятора."""

. . . .print("This car has a " + str(self.battery_size) + "-kWh battery.") . .

class ElectricCar(Car):

"""Представляет аспекты машины, специфические для электромобилей."""

def __init__(self, make, model, year):

"""

Инициализирует атрибуты класса-родителя.

Затем инициализирует атрибуты, специфические для электромобиля.

"""

super().__init__(make, model, year)

(4) . . . .self.battery = Battery()

my_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())

my_tesla.battery.describe_battery()

В точке (1) определяется новый класс с именем Battery, который не наследует ни от одного из других классов. Метод __init__() в точке (2) получает один параметр battery_size, кроме self. Если значение не предоставлено, этот необязательный параметр задает battery_size значение 70. Метод describe_battery() также перемещен в этот класс (3).

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

Все книги серии Библиотека программиста

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