До сих пор я старался показать, что на Python можно работать с классами в стиле, привычном для работы с классами в таких языках как, например, C# или Java. В этой модели класс является декларацией - описанием некоторого множества объектов. Это описание включает описание свойств объектов и их поведения. Свойства объектов задаются полями класса, поведение - методами. Каждый класс имеет конструктор объектов. Если конструктор явно не задан, то в класс добавляется конструктор по умолчанию. Создать объект можно только вызвав конструктор. Все объекты класса в момент создания получают один и тот же набор свойств, значения свойств могут отличаться. Изменить описание класса и заданный набор свойств динамически невозможно.
Эта модель обычно расширяется, поскольку кроме полей, принадлежащих объектам, в классе могут быть заданы поля, принадлежащие классу, существующие в единственном экземпляре и доступные всем объектам - экземплярам класса. В языке C# такие поля объявляются как статические. У класса могут быть и статические методы, работающие только со статическими полями. Сам класс может быть объявлен как статический. Тогда он является модулем, существует в единственном экземпляре, его методы являются сервисами, которые такой класс предоставляет другим классам.
Модель класса Pythonсущественно богаче. Вот основные отличия:
Остановимся более подробно на рассмотрении атрибутов класса, задающих свойства класса и его объектов. В Pythonатрибуты могут быть четырех типов:
Pythonне требует обязательного включения конструктора в описание класса, так что общих атрибутов у объектов может и не быть.set метод. О методах класса Pythonуже многое было сказано, в частности об особенности реализации полиморфизма. Сейчас на примере класса Person и его объектов рассмотрим задание атрибутов всех четырех типов. Вот описание класса Person:
from CreatingStr import CreatingStr
class Person(CreatingStr):
"""
Класс с динамически создаваемыми атрибутами 4-х типов:
Атрибут messageBoard - один для всех экземпляров.
Он может создаваться в момент объявления класса,
либо класс может создавать его динамически.
В данном контексте играет роль доски объявлений (аналог static поля C#)
Атрибуты fam и age создаются конструктором класса.
Эти атрибуты всегда присутствуют в каждом экземпляре класса
и должны быть заданы при создании экземпляра.
Атрибут hobby, создается методом класса setHobby.
Атрибут появляется у экземпляра, если он вызывает метод setHobby.
Не все объекты класса обязаны иметь это свойство.
Индивидуальный атрибут, такой как, например, loveBook
создается экземпляром класса.
"""
messageBoard = "Это доска объявлений. Пишите!"
def __init__(self, fam, age):
self.fam = fam
self.age = age
def setHobby(self, hobby):
self.hobby = hobby
def writeMessage(self, mes, new = "new"):
if new == "new":
Person.messageBoard = mes
else:
#new = "добавляем сообщение на доску"
Person.messageBoard = Person.messageBoard + "\r\n " + mes
Класс Person является наследником инструментального класса CreatingStr, наследуемый метод str которого позволяет выдавать информацию об атрибутах, связанных с объектами класса.
Атрибут messageBoard, заданный на уровне класса, является атрибутом класса. Он не задает свойство, значения которого индивидуальны для каждого из объектов класса. Значение этого свойства доступны всем объектам как для чтения, так и для записи. В данном примере это свойство играет роль доски объявлений.
Конструктор класса init задает два атрибута - fam и age, обязательных для всех объектов.
Метод setHobby позволяет задавать объектам возможный, но не обязательный атрибут Hobby.
Объект класса может иметь и индивидуальный атрибут, не предусмотренный классом.
В класс включен метод writeMessage, позволяющий записывать или дописывать сообщения объектов в доску объявлений - атрибут messageBoard.
Давайте создадим несколько объектов класса Person, у которых наборы атрибутов будут отличаться:
from Person import Person
def test8():
петр = Person("Петр Петров", 18)
анна = Person("Анна Ананьева", 19)
иван = Person("Иван Иванов", 20)
анна.loveBook = "Мастер и Маргарита"
петр.setHobby("Хоккей")
company = [анна, иван, петр]
for pers in company:
print(pers)
print("message: ", Person.messageBoard)
анна.writeMessage("Анна: Приглашаю на встречу 23.01 в 15.00.")
петр.writeMessage("Петр: Приду!", "add")
иван.writeMessage("Иван: Буду!", "add")
print("message: ", Person.messageBoard)
При создании объектов: петр, анна, иван вызывается конструктор класса, позволяющий задать индивидуальные значения обязательных свойств объектов - fam и age.
Объект петр динамически задает предусмотренное классом свойство, вызывая метод setHobby:
петр.setHobby("Хоккей")
Объект anna динамически создает индивидуальный атрибут, выполняя вызов:
анна.loveBook = "Мастер и Маргарита"
В тесте идет работа объектов с общим для всех атрибутом messageBoard. Для этого объекты используют метод writeMessage, позволяющий записывать или дописывать свои сообщения в доску объявлений messageBoard.
Давайте выполним этот тест.
Вот результаты:
Как видите, все три объекта имеют атрибуты age и fam, но состав атрибутов отличается. Объект "анна" создал индивидуальный атрибут, а "петр" - указал хобби. Используя общий атрибут, объекты смогли обменяться сообщениями.
Напомню, классы А и В связаны отношением наследования, если класс А является родительским классом, а класс В - его потомком. В Pythonпринято называть родительский класс суперклассом или надклассом, а класс потомка - подклассом. Наследование является одним из важнейших инструментов ООП, позволяя существенно сократить объем кода за счет повторного использования кода родительских классов. Повторное использование корректно работающего кода способствует корректности всего проекта.
Сейчас более подробно остановимся на другом отношении, связывающем классы, - отношением, которое, следуя общей терминологии, предпочитаю называть отношением "клиент - поставщик". Классы А и В связаны отношением клиент - поставщик, если класс А в своих методах использует сервисы класса В. Класс А в этом случае называется клиентом, а класс В, поставляющий сервисы, - поставщиком. Наиболее часто такое отношение возникает, когда атрибутом класса А является объект класса В. В этом случае такое отношение называют отношением вложенности, поскольку объект класса В вложен (встроен) в класс А. В Pythonтакое отношение называют отношением агрегирования.
Полезно понимать, что отношение наследования представляет отношение "is a" (является), а отношение вложенности - "has a" (имеет).
Если есть два класса - "квадрат" и "прямоугольник", то они связаны отношением наследования. Класс "прямоугольник" - родительский класс, а "квадрат" - его потомок, поскольку каждый квадрат является прямоугольником.
Если есть два класса - "автомобиль" и "двигатель", то они связаны отношением вложенности. Класс "автомобиль" - клиент, а "двигатель" - поставщик, поскольку каждый автомобиль имеет двигатель.
Отношение "клиент - поставщик" не сводится к случаю вложенности, - когда объект одного класса является атрибутом другого класса. Ситуации, связывающие два класса этим отношением, могут быть самыми разными:
Стоит отметить еще одну важную особенность этого отношения. Класс может быть сам себе клиентом. Атрибутом класса может быть объект этого же класса. Такая структура типична для классов, описывающих динамические структуры данных - деревья, графы и другие подобные типы данных. Возможны ситуации, когда класс А является клиентом класса В, а класс В, в свою очередь является клиентом класса А, то есть классы одновременно являются клиентами и поставщиками друг для друга. Представьте два класса husband и wife, описывающих "мужа" и "жену". Каждый из них в качестве атрибута имеет объект другого класса и каждый из них использует сервисы другого класса. В реальном мире объектов отношение "клиент - поставщик" появляется гораздо чаще чем отношение наследования.
Давайте перейдем к рассмотрению некоторого примера, где классы связаны как отношением наследования, так и отношением вложенности. Пусть у нас есть три класса: Person, описывающий людей, Car, описывающий автомобили, и QwnerOfCar, задающий множество людей, владеющих автомобилями.
Напомним, что в Pythonклассы являются не только описаниями некоторого множества, но и сами могут рассматриваться как объекты. Но для нашего рассмотрения этот факт не имеет особого значения. Понятно, что люди и автомобили - это разные сущности, вообще говоря, не связанные друг с другом. Однако некоторые люди владеют автомобилями, и это множество людей можно задать отдельным классом QwnerOfCar. Объекты этого класса являются людьми и имеют автомобили. Поэтому класс QwnerOfCar является наследником класса Person и клиентом класса Car. Рассмотрим подробнее, как устроены эти три класса, построим модели этих сущностей.
Выше этот класс уже рассмотрен. Добавим в него еще пару специализированных set методов:
def setIfStudent(self, status = "student", Institute = "TverTechnicalUniversity"):
self.status = status
self.Institute = Institute
def setIfEmployee(self, status = "employee", position = "engineer"):
self.status = status
self.position = position
Методы позволяют персоне (студенту или служащему) добавить атрибут "статус" и характеристику, связанную со статусом. Конечно, можно было бы ввести общий set метод, задающий произвольный статус, но для нашего примера специализированные статусы предпочтительны, поскольку более информативны.
Объектами этого класса являются автомобили. Мы ограничились заданием ряда характеристик, представленных атрибутами класса. Помимо марки автомобиля, года выпуска, первоначальной цены заданы такие характеристики, как пройденный километраж, текущий владелец авто и список всех владельцев, которым когда-либо принадлежал автомобиль.
Два метода - AddMiles и AddOwner позволяют изменять свойства объектов odometer и owners, добавляя в показания спидометра пройденные километры, в список владельцев - нового владельца.
Вот описание класса:
from CreatingStr import CreatingStr
class Car(CreatingStr):
"""автомобиль"""
def __init__(self, model = "Lada", release_year = 2018, price = 1000000,
odometer = 0, current_owner = "shop", owners = ["shop"]):
self.model = model
self.release_year = release_year
self.price = price
self.odometer = odometer
self.current_owner = current_owner
self.owners = owners
def Add_miles(self,distance):
self.odometer +=distance
def Add_owner(self, owner):
self.owners.append(owner)
Этот класс, используя отношения наследования и вложенности, объединяет классы Person и Car, создавая единую систему взаимодействующих классов.
Приведу описание этого класса:
from Person import Person
from Car import Car
class OwnerOfCar(Person):
"""
персона - владеет автомобилем - объектом car
"""
def __init__(self, fam, age, car = None):
Person.__init__(fam, age)
self.car = car
def BuyCar(self, car, price):
""" покупка автомобиля """
self.car = car
car.price = price
car.current_owner = self.fam
car.Add_owner(self.fam)
def SellCar(self):
""" продажа автомобиля """
self.car = None
def setMyTrips(self, myTrips):
""" список путешествий """
self.myTrips = myTrips
def NewTrip(self, route, distance):
""" новое путешествие """
self.myTrips.append(route)
self.car.Add_miles(distance)
Приведем некоторый сценарий, в котором участвуют две персоны, владеющие автомобилями, и их автомобили. Персоны покупают и продают автомобили, путешествуют на своих любимых авто. Вот соответствующий код сценария:
def test9():
from Car import Car
car_Lada = Car(release_year = 2017, price = 800000, owners = ["shop"])
car_Merc = Car("Mercedes", 2019, 1900000, owners = ["shop"])
from OwnerOfCar import OwnerOfCar
owner_manager = OwnerOfCar("Тригорин Алексей", 35)
owner_manager.setIfEmployee(position = "major manager")
owner_manager.BuyCar(car_Lada, 900000)
owner_manager.setMyTrips([])
owner_manager.NewTrip("Praga", 2500)
owner_manager.SellCar()
owner_manager.BuyCar(car_Merc, 1800000)
owner_manager.NewTrip("Rome", 4500)
owner_stud = OwnerOfCar("Миронов Андрей", 21)
owner_stud.setIfStudent();
owner_stud.BuyCar(car_Lada, 600000)
owner_stud.setMyTrips([])
owner_stud.NewTrip("Moscow", 500)
print('Тригорин: ', owner_manager)
print('Миронов: ',owner_stud)
print('Lada: ', car_Lada)
print('Merc: ',car_Merc)
Вот результаты работы:
Этот пример завершает тему проектирования иерархии классов, связанных отношениями наследования и вложенности.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.