Главная страница
Навигация по странице:

  • 9.2. Три ресторана

  • УПРАЖНЕНИЯ 9.4. Посетители

  • 9.5. Попытки входа

  • Мэтиз. Изучаем Python. Crash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g


    Скачать 6.2 Mb.
    НазваниеCrash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g
    Дата28.06.2022
    Размер6.2 Mb.
    Формат файлаpdf
    Имя файлаМэтиз. Изучаем Python.pdf
    ТипДокументы
    #618322
    страница20 из 52
    1   ...   16   17   18   19   20   21   22   23   ...   52
    173
    Создадим экземпляр, представляющий конкретную собаку:
    class Dog():

    my_dog = Dog('willie', 6)

    print(f"My dog's name is {my_dog.name}.")

    print(f"My dog is {my_dog.age} years old.")
    Использованный в данном случае класс
    Dog был написан в предыдущем примере.
    В точке  мы приказываем Python создать экземпляр собаки с кличкой 'willie'
    и возрастом 6 лет. В процессе обработки этой строки Python вызывает метод
    __init__()
    класса
    Dog с аргументами 'willie'
    и 6. Метод
    __init__()
    создает экзем- пляр, представляющий конкретную собаку, и присваивает его атрибутам name и age переданные значения. Затем Python возвращает экземпляр, представляющий собаку.
    Этот экземпляр сохраняется в переменной my_dog
    . Здесь нелишне вспомнить согла- шения по записи имен: обычно считается, что имя, начинающееся с символа верхнего регистра (например,
    Dog
    ), обозначает класс, а имя, записанное в нижнем регистре
    (например, my_dog
    ), обозначает отдельный экземпляр, созданный на базе класса.
    Обращение к атрибутам
    Для обращения к атрибутам экземпляра используется «точечная» запись. В стро- ке  мы обращаемся к значению атрибута name экземпляра my_dog
    :
    my_dog.name
    Точечная запись часто используется в Python. Этот синтаксис показывает, как
    Python ищет значения атрибутов. В данном случае Python обращается к экзем- пляру my_dog и ищет атрибут name
    , связанный с экземпляром my_dog
    . Это тот же атрибут, который обозначался self.name в классе
    Dog
    . В точке  тот же прием ис- пользуется для работы с атрибутом age
    Пример выводит известную информацию о my_dog
    :
    My dog's name is Willie.
    My dog is 6 years old.
    Вызов методов
    После создания экземпляра на основе класса
    Dog можно применять точечную запись для вызова любых методов, определенных в
    Dog
    :
    class Dog():
    my_dog = Dog('willie', 6)
    my_dog.sit()
    my_dog.roll_over()

    174 Глава 9 • Классы
    Чтобы вызвать метод, укажите экземпляр (в данном случае my_dog
    ) и вызываемый метод, разделив их точкой. В ходе обработки my_dog.sit()
    Python ищет метод sit()
    в классе
    Dog и выполняет его код. Строка my_dog.roll_over()
    интерпретируется аналогичным образом.
    Теперь экземпляр послушно выполняет полученные команды:
    Willie is now sitting.
    Willie rolled over!
    Это очень полезный синтаксис. Если атрибутам и методам были присвоены содер- жательные имена (например, name
    , age
    , sit()
    и roll_over()
    ), разработчик сможет легко понять, что делает блок кода — даже если он видит этот блок впервые.
    Создание нескольких экземпляров
    На основе класса можно создать столько экземпляров, сколько вам потребуется.
    Создадим второй экземпляр
    Dog с именем your_dog
    :
    class Dog():
    my_dog = Dog('willie', 6)
    your_dog = Dog('lucy', 3)
    print(f"My dog's name is {my_dog.name}.")
    print(f"My dog is {my_dog.age} years old.")
    my_dog.sit()
    print(f"\nYour dog's name is {your_dog.name}.")
    print(f"Your dog is {your_dog.age} years old.")
    your_dog.sit()
    В этом примере создаются два экземпляра с именами
    Willie и
    Lucy
    . Каждый эк- земпляр обладает своим набором атрибутов и способен выполнять действия из общего набора:
    My dog's name is Willie.
    My dog is 6 years old.
    Willie is now sitting.
    Your dog's name is Lucy.
    Your dog is 3 years old.
    Lucy is now sitting.
    Даже если второй собаке будет назначено то же имя и возраст, Python все равно создаст отдельный экземпляр класса
    Dog
    . Вы можете создать сколько угодно эк- земпляров одного класса при условии, что эти экземпляры хранятся в переменных с разными именами или занимают разные позиции в списке либо словаре.

    Работа с классами и экземплярами 175
    УПРАЖНЕНИЯ
    9.1. Ресторан: создайте класс с именем
    Restaurant
    . Метод
    __init__()
    класса
    Restaurant должен содержать два атрибута
    :
    restaurant_name и cuisine_type
    . Создайте метод describe_
    restaurant()
    , который выводит два атрибута, и метод open_restaurant()
    , который выводит сообщение о том, что ресторан открыт.
    Создайте на основе своего класса экземпляр с именем restaurant
    . Выведите два атрибута по отдельности, затем вызовите оба метода.
    9.2. Три ресторана: начните с класса из упражнения 9.1. Создайте три разных экземпляра, вызовите для каждого экземпляра метод describe_restaurant()
    9.3. Пользователи: создайте класс с именем
    User
    . Создайте два атрибута first_name и last_
    name
    , а затем еще несколько атрибутов, которые обычно хранятся в профиле пользователя.
    Напишите метод describe_user()
    , который выводит сводку с информацией о пользователе.
    Создайте еще один метод greet_user()
    для вывода персонального приветствия для поль- зователя.
    Создайте несколько экземпляров, представляющих разных пользователей. Вызовите оба метода для каждого пользователя.
    Работа с классами и экземплярами
    Классы могут использоваться для моделирования многих реальных ситуаций. По- сле того как класс будет написан, разработчик проводит большую часть времени за работой с экземплярами, созданными на основе этого класса. Одной из первых задач станет изменение атрибутов, связанных с конкретным экземпляром. Атрибу- ты экземпляра можно изменять напрямую или же написать методы, изменяющие атрибуты по особым правилам.
    Класс Car
    Напишем класс, представляющий автомобиль. Этот класс будет содержать инфор- мацию о типе машины, а также метод для вывода краткого описания:
    car.py
    class Car():
    """Простая модель автомобиля."""

    def __init__(self, make, model, year):
    """Инициализирует атрибуты описания автомобиля."""
    self.make = make self.model = model self.year = year

    def get_descriptive_name(self):
    """Возвращает аккуратно отформатированное описание."""
    long_name = f"{self.year} {self.manufacturer} {self.model}"
    return long_name.title()

    176 Глава 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.
    При желании можно легко усовершенствовать этот метод, чтобы он отклонял отрицательные приращения; тем самым вы предотвратите обратную подкрутку одометра.

    180 Глава 9 • Классы
    ПРИМЕЧАНИЕ Подобные методы управляют обновлением внутренних значений эк- земпляров (таких, как показания одометра), однако любой пользователь, имеющий до- ступ к программному коду, сможет напрямую задать атрибуту любое значение . Эффек- тивная схема безопасности должна уделять особое внимание таким подробностям, не ограничиваясь простейшими проверками .
    УПРАЖНЕНИЯ
    9.4. Посетители: начните с программы из упражнения 9.1 (с. 175). Добавьте атрибут number_served со значением по умолчанию
    0
    ; он представляет количество обслуженных посетителей. Создайте экземпляр с именем restaurant
    . Выведите значение number_served
    , потом измените и выведите снова.
    Добавьте метод с именем set_number_served()
    , позволяющий задать количество обслужен- ных посетителей. Вызовите метод с новым числом, снова выведите значение.
    Добавьте метод с именем increment_number_served()
    , который увеличивает количество об- служенных посетителей на заданную величину. Вызовите этот метод с любым числом, ко- торое могло бы представлять количество обслуженных клиентов, — скажем, за один день.
    9.5. Попытки входа: добавьте атрибут login_attempts в класс
    User из упражнения 9.3
    (с. 175). Напишите метод increment_login_attempts()
    , увеличивающий значение login_
    attempts на
    1
    . Напишите другой метод с именем reset_login_attempts()
    , обнуляющий зна- чение login_attempts
    Создайте экземпляр класса
    User и вызовите increment_login_attempts()
    несколько раз.
    Выведите значение login_attempts
    , чтобы убедиться в том, что значение было измене- но правильно, а затем вызовите reset_login_attempts()
    . Снова выведите login_attempts и убедитесь в том, что значение обнулилось.
    Наследование
    Работа над новым классом не обязана начинаться с нуля. Если класс, который вы пишете, представляет собой специализированную версию ранее написанного класса, вы можете воспользоваться наследованием. Один класс, наследующий от другого, автоматически получает все атрибуты и методы первого класса. Исходный класс называется родителем, а новый класс — потомком. Класс-потомок наследует атрибуты и методы родителя, но при этом также может определять собственные атрибуты и методы.
    Метод __init__() класса-потомка
    При написании нового класса на базе существующего класса часто приходится вы- зывать метод
    __init__()
    класса-родителя. При этом происходит инициализация любых атрибутов, определенных в методе
    __init__()
    родителя, и эти атрибуты становятся доступными для класса-потомка.
    Например, попробуем построить модель электромобиля. Электромобиль пред- ставляет собой специализированную разновидность автомобиля, поэтому новый класс
    ElectricCar можно создать на базе класса
    Car
    , написанного ранее. Тогда

    Наследование 181
    нам останется добавить в него код атрибутов и поведения, относящегося только к электромобилям.
    Начнем с создания простой версии класса
    ElectricCar
    , который делает все, что делает класс
    Car
    :
    electric_car.py
    ❶ 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):
    long_name = f"{self.year} {self.manufacturer} {self.model}"
    return long_name.title()
    def read_odometer(self):
    print(f"This car has {self.odometer_reading} miles on it.")
    def update_odometer(self, mileage):
    if mileage >= self.odometer_reading:
    self.odometer_reading = mileage else:
    print("You can't roll back an odometer!")
    def increment_odometer(self, miles):
    self.odometer_reading += miles

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

    def __init__(self, make, model, year):
    """инициализирует атрибуты класса-родителя."""

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

    my_tesla = ElectricCar('tesla', 'model s', 2019)
    print(my_tesla.get_descriptive_name())
    В точке  строится экземпляр
    Car
    . При создании класса-потомка класс-родитель должен быть частью текущего файла, а его определение должно предшествовать определению класса-потомка в файле. В точке  определяется класс-потомок
    ElectricCar
    . В определении потомка имя класса-родителя заключается в круглые скобки. Метод
    __init__()
    в точке  получает информацию, необходимую для создания экземпляра
    Car
    Функция super()
    в строке  — специальная функция, которая позволяет вы- звать метод родительского класса. Эта строка приказывает Python вызвать метод
    __init__()
    класса
    Car
    , в результате чего экземпляр
    ElectricCar получает доступ

    1   ...   16   17   18   19   20   21   22   23   ...   52


    написать администратору сайта