Занятие № 11. Описание типов пользователя
Цель: научиться создавать собственные классы и объекты.
Теория
Объекты и классы
Все значения в Python являются объектами определённых классов. Чтобы узнать экземпляром какого класса является значение, используем функцию type():
print(type(42))
print(type(3.14))
print(type("Python"))
print(type([1, 1, 2, 3, 5]))
print(type({1: 'I', 2: 'II'}))
Даже функции являются объектами класса function:
def hello():
print("Привет, мир!")
print(type(hello))
Поэтому важно понимать, как можно создать собственный тип данных, если нет подходящего среди стандартных.
Описание класса
Создание собственного класса рассмотрим на примере описания собственного типа Point, который будет хранить информацию о точке не плоскости. Любой объект хранит в себе набор членов класса. К ним относятся поля - состояние объекта и методы - функции, которые меняют состояние объекта.
Простейшее описание класса выглядит так:
Сейчас в классе Point нет ни полей ни методов.
Чтобы создать экземпляр класса или объект этого типа, необходимо записать имя класса с круглыми скобками:
Программа скажет нам, что переменная a ссылается на объект класса <class '__main__.Point'>.
Для обращения к полям и методам класса используется оператор . точка. Вы использовали подобную запись когда, например, добавляли элемент к списку, записывая инструкцию <список>.
x
append(<элемент>).
Последовательно запускайте интерактивные примеры с кодом. Следующий фрагмент кода может зависеть от предыдущего.
Добавить поля к объекту можно также с помощью их записи через точку:
class Point:
pass
a = Point()
a.x = 4.3 # добавляем поле x
a.y = -2.1 # добавляем поле y
# получаем значения из полей x и y
print(a.x, a.y)
Методы класса
Каждый раз задавать значения для полей таким образом неудобно, поэтому объявим функцию init(), которая в качестве аргументов будет принимать объект типа Point и значения полей x и y:
class Point:
pass
def init(p, x, y):
# задаём начальные значения полей
p.x = x
p.y = y
b = Point() # создаём новый объект типа Point
init(b, 3, 5) # инициализируем начальные значения полей
print(b.x, b.y)
Python позволяет поместить функцию инициализации полей класса внутрь описания класса. Для этого в класс добавляется метод __init__(). Первый параметр метода будет ссылкой на объект, который нужно инициализировать. Этот параметр может иметь произвольное имя, но принято называть его self:
Теперь при создании объекта класса можно указать начальные значения полей класса:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
c = Point(-3.4, 11)
print(c.x, c.y)
Посмотрите на последовательное выполнение кода, в котором создаётся объект класса Point.
После выполнения кода в строке
x будет вызван метод __init__().
Опишем ещё одну функцию origin_dist() с помощью которой рассчитаем расстояние от начала координат до заданной точки:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def origin_dist(p):
return (p.x ** 2 + p.y ** 2) ** 0.5
tochka = Point(0, 32)
dist = origin_dist(tochka)
print(dist)
Функцию origin_dist() так же можно оформить как метод класса Point. Как и в случае с __init__(), первый параметр любого метода класса - это ссылка на объект, который нужно обработать:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# метод расчёта расстояния до точки (0,0)
def origin_dist(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
tochka = Point(0, 32)
dist = tochka.origin_dist() # вызываем метод класса
print(dist)
Посмотрите на последовательное выполнение кода в котором используется метод origin_dist() класса Point.
В записи вызова метода tochka.origin_dist() в скобках не указываются аргументы. Подобная запись преобразуется Python в следующий эквивалентный код:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# метод расчёта расстояния до точки (0,0)
def origin_dist(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
tochka = Point(0, 32)
dist = Point.origin_dist(tochka)
print(dist)
Специальные методы класса
Когда мы используем функцию print() и выводим значение выражения того или иного типа, это значение преобразуется в строку. Если попробовать вывести объект класса Point, то получим следующий результат:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
c = Point(-9, 16)
print(c)
Результат не показывает содержимого полей класса. Чтобы определить, как преобразовать объект класса в строку, в его определении нужно добавить специальный метод __str__(). Добавим этот метод к объявлению класса Point, чтобы выводить координаты точки:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def origin_dist(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
def __str__(self):
return f"x={self.x}, y={self.y}"
v = Point(-9, 16)
print(v) # выводим объект v на экран; будет вызван метод __str__()
Специальные методы позволяют реализовать в собственном классе функции доступные для других типов объектов.
Примеры
Пример № 1 (ex01.py)
Опишите класс MSDice который реализует многогранную игральную кость. Описание класса содержит количество граней и текущее значение.
from random import randint
class MSDice:
"""Описание класса"""
def __init__(self, sides):
"""Конструктор класса"""
self.sides = sides
self.value = 1
def roll(self):
"""Бросок кубика"""
self.value = randint(1, self.sides)
def getValue(self):
"""Получаем значение, выпавшее на кубике"""
return self.value
def setValue(self, value):
"""Меняем значение на произвольное"""
self.value = value
die20 = MSDice(20) # создаём игровой кубик с 20 гранями
print(die20.getValue()) # выводим текущее значение на кубике
die20.roll() # "бросаем" кубик
print(die20.getValue()) # выводим текущее значение на кубике
die20.setValue(8) # меняем значение на 8
print(die20.getValue())
За пошаговым выполнением программы можно проследить, перейдя по следующей ссылке.
Задания для самостоятельной работы
Задание № 1 (sam01.py)
Опишите класс Robot, содержащий одно поле model и метод sayHi(name). Метод должен поприветствовать человека, чьё имя указано в параметре name.
Для написания программы используйте следующий шаблон. Вместо комментариев в методе __init__ и say_Hi напишите их реализацию.
Шаблон:
class Robot:
def __init__(self, model):
# сохраняем модель робота в поле с именем model
def sayHi(self, name):
# метод должен вывести сообщение
# Привет, <name>. Меня зовут <model>.
# следующий код оставьте без изменений
bender = Robot("Бендер")
bender.sayHi("Фрай")
term = Robot("T-800")
term.sayHi("Сара Конор")Пример:
Привет, Фрай. Меня зовут Бендер
Привет, Сара Конор. Меня зовут T-800
Задание № 2 (sam02.py)
Опишите класс Student. Класс должен содержать следующие поля:
last_name- фамилия студента (строка)course- номер курса, на котором студент учится (целое число)
Класс должен содержать следующие методы:
__init__(last_name, course)- конструктор, который создаёт объект и сохраняет нужные поляprintInfo()- выводит на экран информацию о студенте (см. пример)getCourse() -возвращает значение поляcoursesetCourse(new_course)- меняет текущий номер курса наnew_course
Для написания программы используйте следующий шаблон.
Шаблон:
Пример:
Фамилия: Иванов; учится на 2 курсе
Номер курса: 2
Переводим на следующий курс
Номер курса: 3
Задание № 3 (sam03.py)
Создайте класс Player, описывающий игрока у которого есть следующие поля:
nickname- имя игрока (строка)exp_points- количество очков опыта (целое число); начальное значение - 0inventory- список предметов, которые есть у игрока (список); начальное значение - []
Класс должен содержать следующие методы:
__init__(nickname)- конструктор, принимающий в качестве параметра имя игрока. Также конструктор инициализирует поляexp_points=0иinventory=[]__str__- преобразование объекта в строку (формат вывода см. в примере)addExp(exp)- добавить игрокуexpочков опытаaddItem(item)- добавить к спискуinventoryпредметitem(строка)removeItem(item)- удалить из спискаinventoryпредмет с именемitem(строка)
Для написания программы используйте следующий шаблон.
Шаблон:
# тут расположите описание класса Player
# следующий код оставьте без изменений
novice = Player("MegaPro") # создание объекта
print(novice) # вывод информации об объекте (будет вызван метод __str__)
novice.addExp(100) # добавляем 100 очков опыта
novice.addItem("броня") # добавляем предмет к инвентарю
novice.addItem("меч") # добавляем предмет к инвентарю
print(novice) # вывод информации об объекте
novice.addExp(50) # добавляем 50 очков опыта
novice.removeItem("броня") # удаляем предмет из инвентаря
print(novice)Пример:
MegaPro - 0 exp. - []
MegaPro - 100 exp. - ['броня', 'меч']
MegaPro - 150 exp. - ['меч']
Задание № 4 (sam04.py)
С помощью ООП реализуйте модель корзины для магазина. Объект с товаром содержит его название и цену. Корзина содержит электронную почту заказчика и список товаров. Опишите два класса - Item (Товар) и Cart (Корзина).
Поля класса Item:
title- название товара (строка)price- цена товара (целое число)
Методы класса Item:
__init__(title, price)- конструктор классаgetPrice()- возвращает цену товара__str__() - Преобразование объекта в строку (формат вывода см. в примере)
Поля класса Cart:
email- электронная почта заказчика (строка)items- список товаров в корзине (список)
Методы класса Cart:
__init__(email)- конструктор класса; полеitemsинициализируется пустым списком []addItem(item)- добавить заказ к списку, который хранится в полеitemsgetTotalPrice()- возвращает общую стоимость всех товаров в корзинеprintOrder()- выводит на экран список всех товаров в корзине (формат вывода см. в примере)
Для написания программы используйте следующий шаблон.
Шаблон:
# тут расположите описание класса Item
# тут расположите описание класса Cart
# следующий код оставьте без изменений
apple = Item("Яблоко", 20) # создаём товар
pen = Item("Ручка", 10) # создаём товар
print(apple) # выводим информацию о товаре (будет вызван метод __str__)
print("Цена товара:", apple.getPrice()) # получаем цену товара
my_cart = Cart("user@mail.com") # создаём корзину
my_cart.addItem(apple) # добавляем первый товар в корзину
my_cart.addItem(pen) # добавляем второй товар в корзину
my_cart.printOrder() # выводит список товаров в корзине
print("Сумма:", my_cart.getTotalPrice()) # получаем общую стоимость заказаПример:
Яблоко - 20 руб.
Цена товара: 20
Товары в корзине:
Яблоко - 20 руб.
Ручка - 10 руб.
Сумма: 30