Наследование
183
В точке
добавляется новый атрибут
self.battery_size
, которому присваивается
исходное значение — скажем, 75. Этот атрибут будет присутствовать во всех экзем-
плярах, созданных на основе класса
ElectricCar
(но не во всяком экземпляре
Car
).
Также добавляется метод с именем
describe_battery()
, который выводит инфор-
мацию об аккумуляторе в точке
. При вызове этого метода выводится описание,
которое явно относится только к электромобилям:
2019 Tesla Model S
This car has a 75-kWh battery.
Возможности специализации класса
ElectricCar
беспредельны. Вы можете до-
бавить сколько угодно атрибутов и методов, чтобы моделировать электромобиль
с любой нужной точностью. Атрибуты или методы, которые могут принадлежать
любой машине (а не только электромобилю), должны добавляться в класс
Car
вместо
ElectricCar
. Тогда эта информация будет доступна всем пользователям
класса
Car
, а класс
ElectricCar
будет содержать только код информации и пове-
дения, специфических для электромобилей.
Переопределение
методов класса-родителя
Любой метод родительского класса, который в моделируемой ситуации делает не
то, что нужно, можно переопределить. Для этого в классе-потомке определяется
метод с тем же именем, что и у метода класса-родителя. Python игнорирует метод
родителя и обращает внимание только на метод, определенный в потомке.
Допустим, в классе
Car
имеется метод
fill_gas_tank()
. Для электромобилей за-
правка бензином бессмысленна, поэтому этот метод логично переопределить. На-
пример, это можно сделать так:
class ElectricCar(Car):
...
def fill_gas_tank(self):
"""У электромобилей нет бензобака."""
print("This car doesn't need a gas tank!")
И если кто-то попытается вызвать метод
fill_gas_tank()
для электромобиля,
Python проигнорирует метод
fill_gas_tank()
класса
Car
и выполнит вместо него
этот код. С применением наследования потомок сохраняет те аспекты родителя,
которые
вам нужны, и переопределяет все ненужное.
Экземпляры как атрибуты
При моделировании явлений реального мира в программах классы нередко до-
полняются все большим количеством подробностей. Списки атрибутов и мето-
дов растут, и через какое-то время файлы становятся длинными и громоздкими.
В такой ситуации часть одного класса нередко можно записать в виде отдельного
184
Глава 9 • Классы
класса. Большой код разбивается на меньшие классы, которые работают во взаи-
модействии друг с другом.
Например, при дальнейшей доработке класса
ElectricCar
может оказаться, что
в нем появилось слишком много атрибутов и методов, относящихся к аккумулято-
ру. В таком случае можно остановиться и переместить
все эти атрибуты и методы
в отдельный класс с именем
Battery
. Затем экземпляр
Battery
становится атрибу-
том класса
ElectricCar
:
class Car():
...
❶
class Battery():
"""Простая модель аккумулятора электромобиля."""
❷
def __init__(self, battery_size=75):
"""Инициализирует атрибуты аккумулятора."""
self.battery_size = battery_size
❸
def describe_battery(self):
"""Выводит информацию о мощности аккумулятора."""
print(f"This car has a {self.battery_size}-kWh battery.")
class ElectricCar(Car):
"""Представляет аспекты машины, специфические для электромобилей."""
def __init__(self, make, model, year):
"""
Инициализирует атрибуты класса-родителя.
Затем инициализирует атрибуты, специфические для электромобиля.
"""
super().__init__(make, model, year)
❹
self.battery = Battery()
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
В точке
определяется новый класс с именем
Battery
, который не наследует
ни один из других классов. Метод
__init__()
в точке
получает один параметр
battery_size
, кроме
self
. Если значение не предоставлено, этот необязательный
параметр задает
battery_size
значение 75. Метод
describe_battery()
также пере-
мещен в этот класс
.
Затем в класс
ElectricCar
добавляется атрибут с именем
self.battery
. Эта стро-
ка приказывает Python создать новый экземпляр
Battery
(со значением
battery_
size
по умолчанию, равным 75, потому что значение не задано) и сохранить его
в атрибуте
self.battery
. Это будет происходить при каждом вызове
__init__()
;
теперь любой экземпляр
ElectricCar
будет иметь автоматически создаваемый
экземпляр
Battery
.