Глава 9 • Классы
❸
my_new_car = Car('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())
В точке
в классе
Car
определяется метод
__init__()
; его список параметров на-
чинается с
self
, как и в классе
Dog
. За ним следуют еще три параметра:
make
,
model
и
year
. Метод
__init__()
получает эти параметры и сохраняет их в атрибутах, ко-
торые будут связаны с экземплярами, созданными на основе класса. При создании
нового экземпляра
Car
необходимо указать фирму-производитель, модель и год
выпуска для данного экземпляра.
В точке
определяется метод
get_descriptive_name()
, который объединяет год
выпуска, фирму-производитель и модель в одну строку с описанием. Это избавит
вас от необходимости выводить значение каждого атрибута по отдельности. Для
работы со значениями атрибутов в этом методе используется синтаксис
self.make
,
self.model
и
self.year
. В точке
создается экземпляр класса
Car
, который со-
храняется в переменной
my_new_car
. Затем вызов метода
get_descriptive_name()
показывает, с какой машиной работает программа:
2019 Audi A4
Чтобы класс был более интересным, добавим атрибут, изменяющийся со време-
нем, — в нем будет храниться пробег машины в милях.
Назначение атрибуту значения по умолчанию
Каждый атрибут класса должен иметь исходное значение, даже если оно равно 0
или пустой строке. В некоторых случаях (например, при задании значений по
умолчанию) это исходное значение есть смысл задавать в теле метода
__init__()
;
в таком случае передавать параметр для этого атрибута при создании объекта не
обязательно.
Добавим атрибут с именем
odometer_reading
, исходное значение которого всегда
равно 0. Также в класс будет включен метод
read_odometer()
для чтения текущих
показаний одометра:
class Car():
def __init__(self, make, model, year):
"""Инициализирует атрибуты описания автомобиля."""
self.make = make
self.model = model
self.year = year
❶
self.odometer_reading = 0
def get_descriptive_name(self):
...
❷
def read_odometer(self):
"""Выводит пробег машины в милях."""
Работа с классами и экземплярами
177
print(f"This car has {self.odometer_reading} miles on it.")
my_new_car = Car('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
Когда Python вызывает метод
__init__()
для создания нового экземпляра, этот
метод сохраняет фирму-производителя, модель и год выпуска в атрибутах, как
и в предыдущем случае. Затем Python создает новый атрибут с именем
odometer_
reading
и присваивает ему исходное значение 0
. Также в класс добавляется
новый метод
read_odometer()
, который упрощает чтение пробега машины
в милях.
Сразу же после создания машины ее пробег равен 0:
2019 Audi A4
This car has 0 miles on it.
Впрочем, у продаваемых машин одометр редко показывает ровно 0, поэтому нам
понадобится способ изменения значения этого атрибута.
Изменение значений атрибутов
Значение атрибута можно изменить одним из трех способов: изменить его прямо
в экземпляре, задать значение при помощи метода или изменить его с приращением
(то есть прибавлением определенной величины) при помощи метода. Рассмотрим
все эти способы.
Прямое изменение значения атрибута
Чтобы изменить значение атрибута, проще всего обратиться к нему прямо через эк-
земпляр. В следующем примере на одометре напрямую выставляется значение 23:
class Car:
...
my_new_car = Car('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())
❶
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
В точке
точечная запись используется для обращения к атрибуту
odometer_
reading
экземпляра и прямого присваивания его значения. Эта строка приказывает
Python взять экземпляр
my_new_car
, найти связанный с ним атрибут
odometer_
reading
и задать значение атрибута равным 23:
2019 Audi A4
This car has 23 miles on it.
178
Глава 9 • Классы
Иногда подобные прямые обращения к атрибутам допустимы, но чаще разработчик
пишет вспомогательный метод, который изменяет значение за него.
Изменение значения атрибута с использованием метода
В класс можно включить методы, которые изменяют некоторые атрибуты за вас.
Вместо того чтобы изменять атрибут напрямую, вы передаете новое значение ме-
тоду, который берет обновление атрибута на себя.
В следующем примере в класс включается метод
update_odometer()
для изменения
показаний одометра:
class Car:
...
❶
def update_odometer(self, mileage):
"""Устанавливает заданное значение на одометре."""
self.odometer_reading = mileage
my_new_car = Car('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())
❷
my_new_car.update_odometer(23)
my_new_car.read_odometer()
Класс
Car
почти не изменился, в нем только добавился метод
update_odometer()
.
Этот метод получает пробег в милях и сохраняет его в
self.odometer_reading
.
В точке
мы вызываем метод
update_odometer()
и передаем ему значение 23
в аргументе (соответствующем параметру
mileage
в определении метода). Метод
устанавливает на одометре значение 23, а метод
read_odometer()
выводит текущие
показания:
2019 Audi A4
This car has 23 miles on it.
Метод
update_odometer()
можно расширить так, чтобы при каждом изменении
показаний одометра выполнялась некоторая дополнительная работа. Добавим
проверку, которая гарантирует, что никто не будет пытаться сбрасывать показания
одометра:
class Car():
...
def update_odometer(self, mileage):
"""
Устанавливает на одометре заданное значение.
При попытке обратной подкрутки изменение отклоняется.
"""
❶
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
❷
print("You can't roll back an odometer!")
Работа с классами и экземплярами
179
Теперь
update_odometer()
проверяет новое значение перед изменением атрибута.
Если новое значение
mileage
больше или равно текущему,
self.odometer_reading
,
показания одометра можно обновить новым значением
. Если же новое значение
меньше текущего, вы получите предупреждение о недопустимости обратной под-
крутки
.
Изменение значения атрибута с приращением
Иногда значение атрибута требуется изменить с заданным приращением (вместо
того, чтобы присваивать атрибуту произвольное новое значение). Допустим, вы
купили подержанную машину и проехали на ней 100 миль с момента покупки.
Следующий метод получает величину приращения и прибавляет ее к текущим
показаниям одометра:
class Car():
...
def update_odometer(self, mileage):
...
❶
def increment_odometer(self, miles):
"""Увеличивает показания одометра с заданным приращением."""
self.odometer_reading += miles
❷
my_used_car = Car('subaru', 'outback', 2015)
print(my_used_car.get_descriptive_name())
❸
my_used_car.update_odometer(23_500)
my_used_car.read_odometer()
❹
my_used_car.increment_odometer(100)
my_used_car.read_odometer()
Новый метод
increment_odometer()
в точке
получает расстояние в милях
и прибавляет его к
self.odometer_reading
. В точке
создается экземпляр
my_used_car
. Мы инициализируем показания его одометра значением 23 500;
для этого вызывается метод
update_odometer()
, которому передается значение
23 500
. В точке
вызывается метод
increment_odometer()
, которому передает-
ся значение 100, чтобы увеличить показания одометра на 100 миль, пройденные
с момента покупки:
2015 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.
При желании можно легко усовершенствовать этот метод, чтобы он отклонял
отрицательные приращения; тем самым вы предотвратите обратную подкрутку
одометра.
|