М97 Изучаем Python: программирование игр, визуализация данных, веб-приложения



Pdf көрінісі
бет131/334
Дата18.10.2023
өлшемі6,19 Mb.
#186390
1   ...   127   128   129   130   131   132   133   134   ...   334
Байланысты:
Изучаем Python


Глава 9 • Классы
ко всем атрибутам класса-родителя. Имя 
super
происходит из распространенной 
терминологии: класс-родитель называется 
суперклассом
, а класс-потомок — 
под-
классом
.
Чтобы проверить, правильно ли сработало наследование, попробуем создать элек-
тромобиль с такой же информацией, которая передается при создании обычного 
экземпляра 
Car
. В точке 

мы создаем экземпляр класса 
ElectricCar
и сохраняем 
его в 
my_tesla
. Эта строка вызывает метод 
__init__()
, определенный в 
ElectricCar

который, в свою очередь, приказывает Python вызвать метод 
__init__()
, определен-
ный в классе-родителе 
Car
. При вызове передаются аргументы 
'tesla'

'model
s'
и 
2019
.
Кроме 
__init__()
, класс еще не содержит никаких атрибутов или методов, специ-
фических для электромобилей. Пока мы просто убеждаемся в том, что класс 
электромобиля содержит все поведение, присущее классу автомобиля:
2019 Tesla Model S
Экземпляр 
ElectricCar
работает так же, как экземпляр 
Car
; можно переходить 
к определению атрибутов и методов, специфических для электромобилей.
Определение атрибутов и методов класса-потомка
После создания класса-потомка, наследующего от класса-родителя, можно пере-
ходить к добавлению новых атрибутов и методов, необходимых для того, чтобы 
потомок отличался от родителя.
Добавим атрибут, специфический для электромобилей (например, мощность 
аккумуляторa), и метод для вывода информации об этом атрибуте:
class Car():
...
class ElectricCar(Car):
"""Представляет аспекты машины, специфические для электромобилей."""
def __init__(self, make, model, year):
"""
Инициализирует атрибуты класса-родителя.
Затем инициализирует атрибуты, специфические для электромобиля.
"""
super().__init__(make, model, year)

self.battery_size = 75

def describe_battery(self):
"""Выводит информацию о мощности аккумулятора."""
print(f"This car has a {self.battery_size}-kWh battery.")
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()


Наследование
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
.


Наследование
185
Программа создает экземпляр электромобиля и сохраняет его в переменной 
my_
tesla
. Когда потребуется вывести описание аккумулятора, необходимо обратиться 
к атрибуту 
battery
:
my_tesla.battery.describe_battery()
Эта строка приказывает Python обратиться к экземпляру 
my_tesla
, найти его 
атрибут 
battery
и вызвать метод 
describe_battery()
, связанный с экземпляром 
Battery
из атрибута.
Результат выглядит так же, как и в предыдущей версии:
2019 Tesla Model S 
This car has a 75-kWh battery.
Казалось бы, новый вариант требует большой дополнительной работы, но теперь 
аккумулятор можно моделировать с любой степенью детализации без загромож-
дения класса 
ElectricCar
. Добавим в 
Battery
еще один метод, который выводит 
запас хода на основании мощности аккумулятора:
class Car():
...
class Battery():
...

def get_range(self):
"""Выводит приблизительный запас хода для аккумулятора."""
if self.battery_size == 75:
range = 260
elif self.battery_size == 100:
range = 315
print(f"This car can go about {range} miles on a full charge.")
class ElectricCar(Car):
...
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()

my_tesla.battery.get_range()
Новый метод 
get_range()
в точке 

проводит простой анализ. Если мощность 
равна 75, то 
get_range()
устанавливает запас хода 260 миль, а при мощности 
100 кВт/ч запас хода равен 315 милям. Затем программа выводит это значение. 
Когда вы захотите использовать этот метод, его придется вызывать через атрибут 
battery
в точке 

.
Результат сообщает запас хода машины в зависимости от мощности аккумуля-
тора:


186

Достарыңызбен бөлісу:
1   ...   127   128   129   130   131   132   133   134   ...   334




©engime.org 2024
әкімшілігінің қараңыз

    Басты бет