X-PDF

Разговоры о важном

Поделиться статьей

 

Задорожный С.С., Фадеев Е. П.

Объектноориентированное программирование

на языке Python

Учебнометодическое пособие по дисциплине 

«Введение в компьютерные технологии»

Москва 

Физический факультет МГУ имени М.В. Ломоносова 

2022

            

 

Задорожный Сергей Сергеевич, Фадеев Егор Павлович Объектноориентированное программирование на языке Python

М. : Физический факультет МГУ им. М. В. Ломоносова, 2022. – 49 с.

Впоследнее время языки сценариев, такие как Python, набирают популярность. На них написано больше программного обеспечения, чем на традиционных системных языках. Язык Python доступен для всех основных платформ и активно применяется в научных вычислениях, машинном обучении, вебразработке, создании игр и визуальных эффектов, и ряде других направлений

ЯзыкPython позволяет писать программы в традиционном процедурном стиле, однако крупные проекты имеет смысл разрабатывать, используя парадигму объектноориентированного программирования (ООП). В языке Python ООП играет ключевую роль, т.к. практически все сущности языка представляют собой объекты.

Посравнению со многими другими языками в Python объектноориентированное программирование обладает рядом особых черт, которые следует внимательно рассмотреть при освоении языка. Целью пособия является помощь студентам по освоению этих особенностей

Рассмотрен ряд программ иллюстрирующих создание собственных классов.

Приведен обширный список литературы (втом числе и интернет ресурсов), который поможет выбрать наиболее подходящее издание в соответствии с пожеланиями и уровнем подготовки

Пособие поможет студентам более самостоятельно и оперативно решать задачи практикума по программированию.

Рассчитано настудентов первого и второго курсов физического факультета, но может быть полезно студентам старших курсов, аспирантам и сотрудникам, занимающимися разработкой программного обеспечения на языке Python.

Авторысотрудники кафедры математического моделирования и информатики  физического факультета МГУ.

Рецензенты: доцент кафедры ОФиВП Коновко А.А., ведущий электроник каф. ОФиВП Лукашев А.А.

Подписано в печать                 . Объем   3,5 п.л. Тираж  30 экз. Заказ                   .

Физический факультет им. М. В. Ломоносова

119991 Москва, ГСП-1, Ленинские горы, д. 1, стр. 2.

Отпечатано в отделе оперативной печати физического факультета МГУ.

©Физический факультет МГУим. М. В. Ломоносова,2022 ©Фадеев Е.П., 2022

©Задорожный С.С., 2022

   

Оглавление

1.                  Введение…………………………………………………………………………………………………….4

2.                  Типы данных. Переменные…………………………………………………………………………5

3.                  Вывод данных. Функция print()……………………………………………………………………6

4.                  Ввод данных. Функция input()……………………………………………………………………..7

5.                  Логические выражения и условныеоператоры……………………………………………. 7

6.                  Списки……………………………………………………………………………………………………….9

7.                  Циклы……………………………………………………………………………………………………….10

8.                  Функции…………………………………………………………………………………………………..13

9.                  Модули…………………………………………………………………………………………………….15

10.              Объектноориентированное программирование…………………………………….. 17

11.              Создание классов и объектов…………………………………………………………………. 18

12.              Наследование…………………………………………………………………………………………21

13.              Множественное наследование……………………………………………………………….. 23

14.              Перегрузка операторов…………………………………………………………………………..23

15.              Абстрактные методы……………………………………………………………………………..26

 Ограничение доступа к атрибутамкласса…………………………………………………….. 28

16.              …………………………………………………………………………………………………………………….28

17.              Полиморфизм………………………………………………………………………………………..28

18.              Композиция…………………………………………………………………………………………..29

19.              Статические методы………………………………………………………………………………30

20.              Примеры объектноориентированных программ на Python …………………….. 31

        Класс рациональных дробей…………………………………………………………………..32

        Класс «Студент»……………………………………………………………………………………33

        Виртуальная модель процесса обучения………………………………………………… 34

        Играстратегиия «Солдаты и герои»………………………………………………………. 34

        Класс «Битва»………………………………………………………………………………………..36

        Класс «Колода карт»………………………………………………………………………………37

        Класс «Паспорт» ……………………………………………………………………………………38

        Класс «Склад оргтехники»……………………………………………………………………..39

        Задача трёх тел………………………………………………………………………………………40

21.              Задания для самостоятельного решения…………………………………………………. 42

22.              Литература…………………………………………………………………………………………….49

        Сайты:…………………………………………………………………………………………………..49

        Онлайн IDE/VM…………………………………………………………………………………….49

        Ресурсы о популярных дополнениях……………………………………………………… 49

                  1.         Введение

Python (в русскомпрограммистском сообществе прижилось название «Питон», но правильнеебудет «Пайтон») – это язык сдинамической типизацией данных, который поддерживает многие парадигмы программирования: процедурное, ООП, функциональное

Достоинстваязыка:

     Удобный синтаксис.

     Скорость разработки.

     Большое количество сахара от разработчиков языка.

     Кроссплатформенность(достаточно наличия необходимых библиотек и интерпретатора,чтобы запустить вашу программуна другой ОС).

     Большое количество библиотек позволяет не изобретатьвелосипеды.

     Широко используется (компания Google использует Python в своей поисковой системе, компании Intel, Cisco, Hewlett-Packard,Seagate, Qualcomm, IBM используютPython для тестирования аппаратного обеспечения, компании JPMorgan Chase, UBS, Getco и Citadel применяют Python для прогнозирования финансового рынка, , служба коллективного использования видеоматериалов YouTube и популярная программа BitTorrent для обмена файлами в пиринговыхсетях тоже написаны на языкеPython, NASA, Los Alamos, JPL иFermilab используютPython для научных вычислений).

 

Циклы, ветвления и функциивсе это элементы структурного программирования. Его возможностейвполне хватает для написаниянебольших, простых программ и сценариев.Однако крупные проекты часто реализуют, используя парадигму объектноориентированного программирования (ООП). Вязыке Python ООП играет ключевую роль. Дажепрограммируя в рамках структурной модели, вы всеравно пользуетесь объектами и классами,пусть даже встроенными в язык,а не созданными лично вами.

В Python все объекты являются производными классов и наследуютот них атрибуты. При этомкаждый объект формирует собственное пространство имен. Python поддерживает такиеключевые особенности объектноориентированного программирования как наследование,инкапсуляцию и полиморфизм

Полиморфизмпозволяет объектам разных классов иметь схожие интерфейсы. Он реализуетсяпутем объявления в нихметодов с одинаковыми именами. К проявлениюполиморфизма как особенности ООП такжеможно отнести методы перегрузки операторов.

Кроме наследования, инкапсуляции и полиморфизмасуществуют другие особенности ООП. Таковойявляется композиция, или агрегирование,когда класс включает в себявызовы других классов. В результатепри создании объекта от классаагрегата, создаются объекты других классов, являющиеся составными частями первого

Преимущества ООП

Особенностиобъектноориентированного программирования наделяют его рядомпреимуществ.

Так ООП позволяет использовать один итот же программный код сразными данными. На основеклассов создается множество объектов, у каждогоиз которых могут быть собственныезначения полей. Нет необходимостивводить множество переменных, т.к.объекты получают в своераспоряжение индивидуальные пространства имен. Вэтом смысле объекты похожи на структурыданных. Объект можно представить в виденекой упаковки данных, к которойприсоединены инструменты для ихобработкиметоды.

Наследованиепозволяет не писать новый код, аиспользовать и настраивать уже существующийза счет добавления и переопределенияатрибутов

Недостатки ООП

ООП позволяет оптимизировать дальнейшую поддержку разрабатываемого приложения, однако предполагает большую роль предварительногоанализа предметной области и проектирования.От правильности решений на этомэтапе зависит куда больше,чем от непосредственного написания исходного кода

Следует понимать, что однаи та же задачаможет быть решена разными объектными моделями, каждая из которыхбудет иметь свои преимуществаи недостатки. Только опытный разработчик может сказать, какую из нихбудет проще расширять и обслуживатьв дальнейшем.

Особенности ООП в Python

По сравнению со многимидругими языками в Python объектноориентированное программирования обладает рядом особых черт.

Всё является объектомчисло, строка, список, функция, экземпляр класса, сам класс,модуль. Так классобъект, способный порождать другие объектыэкземпляры.

ВPython нет просто типов данных. Все типыэто классы.

Инкапсуляциив Python не уделяется особого внимания. В другихязыках программирования обычно нельзя получить напрямую доступ к свойству,описанному в классе. Для егоизменения может быть предусмотренспециальный метод. В Python жене считается предосудительным непосредственное обращение к свойствам.

                  2.          Типы данных. Переменные.

В реальной жизни мы совершаемразличные действия над окружающиминас предметами, или объектами.Мы меняем их свойства,наделяем новыми функциями. По аналогиис этим компьютерные программы также управляют объектами, только виртуальными, цифровыми. Будем называть такие объекты данными.

Очевидно, данные бывают разными. Часто компьютерной программе приходится работать с числамии строками. Числа в своюочередь также бывают разными: целыми, вещественными, могут иметь огромное значение или оченьдлинную дробную часть

При знакомстве с языкомпрограммированияPython мы столкнемся с тремятипами данных:

     целые числа (тип int) – положительные и отрицательныецелые числа, а также0 (например, 4, 687,-45, 0).

     числа с плавающей точкой (тип float ) – дробные, они жевещественные, числа (например, 1.45, -3.789654, 0.00453).

     строки (тип str) — набор символов, заключенных в кавычки(например, ball,What is your name?, dkfjUUv, 6589). Кавычки в Python могутбыть одинарными или двойными.Одиночный символ в кавычкахтакже является строкой, отдельного символьного типа вPython нет.

Данные хранятся в памятикомпьютера. Когда мы вводимчисло, оно помещается в какуюто ячейку памяти. Но какпотом узнать, куда именно? Механизм связи между переменными и даннымиможет различаться в зависимостиот языка программирования и типовданных. Для этого данные связываются с какимлибо именем и вдальнейшем обращение к нимвозможно по этому именипеременной

Словопеременнаяобозначает, что сущность может меняться, она непостоянна.

Одна и та жепеременная может быть связанасначала с одними данными, а потомс другими. То естьее значение может меняться, она переменчива.

В программе на языкеPython, как и на большинстведругих языков, связь между данными и переменнымиустанавливается с помощью знака =. Такая операция называется присваивание. Например, выражение sq = 4 означает, что наобъект, представляющий собой число 4, находящееся в определеннойобласти памяти, теперь ссылается переменная sq, и обращаться к этомуобъекту следует по имениsq. Обратите внимание на этуособенность переменных в Python. Еслитеперь написать sq=1, то sq будет ссылаться на другойобъект, представляющий собой число 1. Т.е.все переменные в Python являютсяссылками, переменных закрепленных за фиксированнымадресом памяти (как вязыке С) нет, соответственнонет и указателей.

                  3.          Вывод данных. Функция print() 

Длявывода данных на экраниспользуется функция print().

Можно передавать в функциюprint() как непосредственно литералы, так ипеременные, вместо которых будут выведены их значения.Аргументы функции разделяются между собой запятыми. В выводевместо запятых значения разделены пробелом. Если в скобкахстоит выражение, то сначалаоно выполняется, после чего print() уже выводитрезультат данного выражения:

print(hello + + world) # вывод: hello world

print(10 -2.5/2)   #вывод:   8.75

В функции предусмотрены дополнительные параметры. Например, через параметр sep можно указать отличный от пробеларазделитель строк:

print(Mon, Tue, Wed, Thu, Fri, Sat, Sun, sep=

#вывод:Mon-Tue-Wed-Thu-Fri-Sat-Sun print(1, 2, 3, sep=//) #вывод:1//2//3

Параметр endпозволяет указывать, что делать,после вывода строки. По умолчаниюпроисходит переход на новуюстроку. Однако это действиеможно отменить, указав любой другой символ или строку:print(10, end=:) # вывод: 10:

В функцию print() нередко передаются так называемыеформатированные строки, хотя по смыслуих правильнее называть строкишаблоны. Никакого отношения к самойprint()они не имеют. Когда такая строка находится в скобкахprint(), интерпретаторсначала согласно заданному в нейформату преобразует ее кобычной строке, после чего передаетрезультат в print().

Форматированиеможет выполняться в такназываемом старом стиле или спомощью строкового метода format. Старый стиль также называют Систилем,так как он схожс тем, как происходитвывод на экран в языкеC:

pupil = Ben old = 16 grade = 9.2 print(Its %s, %d.Level: %.2f %(pupil, old, grade)) 

#вывод: Its Ben, 16. Level: 9.20

Здесь вместо трех комбинацийсимволов %s, %d, %fподставляются значения переменных pupil, old, grade. Буквы s, d, f обозначают типы данныхстроку, целое число, вещественное число

Теперь посмотрим на методformat(): print(This is a {0}.Its {1}..format(ball, red)) 

#вывод: This is a ball. Its red.

print(This is a {0}.Its {1}..format(cat, white)) 

#вывод: This is a cat. Its white. print(This is a {0}. Its {1} {2}..format(1, a, number))  # вывод: This is a 1. Its a number.

В строке в фигурныхскобках указаны номера данных, которые будут сюда подставлены.Далее к строке применяется метод format(). В его скобкахуказываются сами данные (можно использовать переменные). На нулевоеместоподставится первый аргумент метода format(), на место с номером1 – второй и т. д.

В новых релизах Питона появился третий способ создания форматированных строкf-строки. Перед их открывающейкавычкой прописывается буква f. В самой строке внутри фигурных скобок записываются выражения на Python, которыеисполняются, когда интерпретатор преобразует строкушаблон в обычную

a = 10 b = 1.33

c = Box

print(fqty — {a:5}, goods -{c}) # вывод: qty —    10,goods — Box print(fprice — {b + 0.2:.1f})

#вывод: price — 1.5

В примере число 5 после переменной a обозначает количество знакомест, отводимых под выводзначения переменной. В выраженииb + 0.2:.1f сначалавыполняется сложение, после этого значение округляется до одногознака после запятой.

                  4.          Ввод данных. Функция input() 

За ввод в программуданных с клавиатуры в Python отвечаетфункция input() . Когда вызывается эта функция,программа останавливает свое выполнениеи ждет, когда пользователь введет текст. После того, какон нажмет клавишу Enter, функция input() заберет введенный текст и передастего программе. Их можноприсвоить переменной

town=input()user=input()

print(fВас зовут {user}. Вашгород {town})

Чтобы не вводить человека в замешательство,для функции input()  предусмотрен специальный параметрприглашение. Это приглашениевыводится на экран при вызовеinput():

town=input(Ваш город:) user=input(Ваше имя:)

print(fВас зовут {user}. Вашгород {town})

 

 

 

Обратите внимание, что впрограмму поступает строка. Даже если ввестичисло, функция input() все равно вернет его строковоепредставление. Чтобы получить число, надо использовать функции преобразования типов

qty=int(input(Количество:)) price=float(input(Цена:))

print(fЗаплатите {qty*price}рублей)

В данном случае с помощьюфункций int() и float() строковые значения переменных qty и price преобразуются соответственно в целоечисло и вещественное число

                  5.           Логические выражения и условные операторы

Ранее мы познакомились с тремятипами данныхцелыми и вещественнымичислами, а также строками. Введем четвертыйлогический тип данных(тип bool ). У этого типа всегодва возможных значения: True и False.

В программировании False  обычно приравнивают к нулю,а True  – к единице. Здесь также работает правило: всё, чтоне 0 и не пустота,является правдой.

Говоря на естественном языке (например, русском) мы обозначаемсравнения словами равно, больше, меньше. В языках программирования используются специальные знаки, подобные тем, которыеиспользуются в математике: >  (больше), <  (меньше), >=  (больше или равно),<=  (меньше или равно), ==  (равно), !=  (не равно).

Не путайте операцию присваивания значения переменной, обозначаемую в языке Pythonодиночным знаком равно, и операцию сравнения (два знакаравно). Присваивание и сравнениеразные операции

a     = 10

b    = 5

c     = a+b > 14

print(c)   # вывод: True c = a < 14-b print(c)   # вывод: False c = a <= b+5 print(c)   # вывод: True c = a != b print(c)   # вывод: True c = a == b

print(a, b, c) # вывод: 10 5 False

Логическиевыражения типа kByte >= 1023 являются простыми, так какв них выполняется только одна логическаяоперация. Однако, на практикенередко возникает необходимость в болеесложных выражениях. Может понадобиться получить ответа Да или Нет в зависимости от результатавыполнения нескольких простых выражений. В такихслучаях используются специальные операторы, объединяющие два иболее простых логических выражения. Широко используются два операторатак называемые логические И(and) иИЛИ (or).

Чтобы получить True при использовании оператора and, необходимо, чтобы результаты обоих простых выражений, которые связывает данный оператор, были истинными. Если хотя быв одном случае результатом будет False, то и всевыражение будет ложным

x     = 8

y     = 13

print(y < 15and x > 8) #вывод: False

Чтобы получить True при использовании оператора or, необходимо, чтобы результат хотя быодного простого выражения, входящего в составсложного, был истинным. В случаеоператора or выражение становится ложным лишь тогда,когда ложны оба составляющиеего простые выражения

x     = 8

y     = 13

print(y < 15or x > 8) #вывод: True

В языке Python есть еще унарныйлогический оператор not , то есть отрицание.Он превращает правду в ложь,а ложь в правду.Унарный он потому, что применяетсяк одному выражению, стоящему после него. print(not y < 15) # вывод: False

При выполнении кода, взависимости от тех илииных условий, некоторые его участкимогут быть опущены, в товремя как другиевыполнены. Иными словами, в программеможет присутствовать ветвление, которое реализуется условным оператором, который имеет следующий формат:

if <Логическое выражение> :

     <Блок,  выполняемый,  если условие истинно>

[elif <Логическое выражение> :

     <Блок, выполняемый,  если условие истинно>

] [else :

   <Блок, выполняемый,  если все условия ложны>

]

Python считается языком с яснымсинтаксисом и легко читаемым кодом. Это достигаетсясведением к минимуму таких вспомогательных элементов как скобоки точек с запятой.Для разделения выражений используется переход на новуюстроку, а для обозначения вложенных выраженийотступы от началастроки:

a                  = 50 n = 98 if n < 100 :

b                  = n + a #блок выполняемый, еслиусловие истинно else :

   b=0       #блок выполняемый, еслиусловие ложно print(b) #вывод 148

 

Последняя строчка кода print(b) ужене относится к условномуоператору, что обозначено отсутствием перед ней отступа.

В язык Python встроена возможность настоящего множественного ветвления на одномуровне вложенности, которое реализуется с помощьюветок elif. Слово elif образовано от двухпервых букв слова else, к которым присоединено слово if. Это можно перевести как иначеесли. В отличие от else , взаголовке elif обязательно должно быть логическоевыражение также, как взаголовке if:

old = int(input(Ваш возраст: )) print(Рекомендовано:, end= ) if old <6:

    print(Заяц влабиринте)    elif 6 <= old < 12:

    print(Марсианин) elif 12 <= old < 16:

    print(Загадочныйостров) else:

    print(Потоксознания

                  6.         Списки 

Список в Python – это встроенный тип (класс)данных, представляющий собой одну изразновидностей структур данных. Структуру данных можно представить, как сложнуюединицу, объединяющую в себегруппу более простых. Каждая разновидность структур данных имеет свои особенности.Списокэто изменяемая последовательность произвольных элементов.

В большинстве других языков программирования есть такойшироко используемый тип данныхкак массив. В Питонетакого встроенного типа нет.Однако списки условно можно считать аналогом массивов за однимисключением. Составляющие массив элементы должны принадлежать одному типу данных,для списков такого ограничения нет.

Например, массив может содержать только целые числа или тольковещественные числа или толькостроки. Список также может содержать элементы только одного типа, чтоделает его внешне неотличимым от массива.Но вполне допустимо, чтобы в одномсписке содержались как числа,так и строки, а такжечтонибудь еще

Создавать списки можно разными способами. Создадим его простымперечислением элементов: a = [12, 3.85, black, -4]

Итак, у нас имеетсясписок, присвоенный переменной a. В Python списокопределяется квадратными скобками. Он содержитчетыре элемента. Если гдетов программе нам понадобитсявесь этот список, мы получимдоступ к нему, указаввсего лишь одну переменную– a. 

Элементы в списке упорядочены, имеет значение в какомпорядке они расположены. Каждый элемент имеет свой индекс,или номер. Индексация начинается с нуля.В данном случае число 12 имеет индекс 0, строка black – индекс 2. Чтобы извлечь конкретный элемент, надо после имени переменной указать в квадратныхскобках его индекс: print(a[0])

ВPython существует также индексация с конца.Она начинается с -1:

print(a[-1])

Часто требуется извлечь не одинэлемент, а так называемыйсрезчасть списка. В этомслучае указывается индекс первого элемента среза и индексследующего за последним элементом среза: print(a[0:2]) # [12, 3.85]

В данном случае извлекаются первые два элементас индексами 0 и 1. Элементс индексом 2 в срезуже не входит. В такомслучае возникает вопрос, как извлечьсрез, включающий в себяпоследний элемент? Если какойлибо индексне указан, то считается,что имеется в видуначало или конец:

print(a[:3]) # [12, 3.85, black] print(a[2:]) # [black,-4] print(a[:])  # [12, 3.85, black,-4]

Спискиизменяемые объекты. Это значит,что в них можнодобавлять элементы, удалять их, изменятьсуществующие. Проще всего изменить значение элемента. Для этогонадо обратиться к немупо индексу и перезаписатьзначение в заданной позиции: a[1] = 4

Добавлятьи удалять лучше с помощьюспециальных встроенных методов списка: a.append(wood)

a.insert(1, circle)

a.remove(4)

a.pop()

a.pop(2)

Перечень всех методов списка можно посмотреть в интернете,например, на

официальномсайте  https://docs.python.org/3/tutorial/datastructures.html

Можно изменять списки не используяметоды, а с помощьювзятия и объединения срезов:

b = [1, 2, 3,4, 5, 6] b = b[:2] + b[3:]

Здесь берется срез изпервых двух элементов и срез,начиная с четвертого элемента (индекс 3) и доконца. После чего срезыобъединяются с помощью оператора сложения.

Можноизменить не один элемент,а целый срез:

mylist = [ab,ra,ka,da,bra] mylist[0:2] = [10,20] print(mylist) #  [10, 20, ka, da,bra]

                  7.         Циклы

Циклы являются такой же важнойчастью структурного программирования, как условныеоператоры. С помощью циклов можно организовать повторение выполнения участков кода

Язык Python при помощи циклов позволяет компактно записать многие повторяющиеся действия, например, вывод чисел от 1 до100: for x in range (1, 101):  print(x)

Цикл for применяется для перебораэлементов последовательности и имееттакой формат:

   

for <Текущий элемент> in <Последовательность> :    <Инструкции внутри цикла> [else:

    <Блок, выполняемый,  если не использовался оператор break>

]

Здесьприсутствуют следующие конструкции:

       <Последовательность>            –          объект,           поддерживающий    механизм       итерации

(последовательного перебора): строка, список, кортеж, диапазон, словарь и др.

       <Текущий элемент> – на каждой итерации через эту переменнуюдоступен очередной элемент последовательности или ключсловаря.

       <Инструкции внутри цикла> – блок, который будет многократно выполняться.

       Если внутри цикла не использовалсяоператор break, то после завершения выполнения цикла будет выполнен блок винструкции else. Этот блок неявляется обязательным.

Примерперебора букв в слове:for symbol in string:

  print(symbol,  end=  else:

   print(nЦиклвыполнен)

 

Функциейrange  ()  используетсядля  генерации  индексов. Она имеет следующий формат:    range ([<Начало>,  ]<Конец>[,  <Шаг>])

Первый параметр задает начальное значение. Если параметр <Начало> не указан, то поумолчанию используется значение 0. Во втором параметре указывается конечное значение. Следует заметить, что ононе входит в возвращаемыезначения. Если параметр <Шаг> не указан, то используетсязначение 1. Функция возвращает диапазонособый объект, поддерживающий итерационный протокол. С помощьюдиапазона внутри цикла for можно получить значение текущего элемента. В качествепримера умножим каждый элемент списка на 2:

arr =  [1,  2, 3] forin range (len (arr) ) : 

   arr[i]  *= 2

print (arr) # вывод [2,4,6]

 

Цикл while

Выполнениеинструкций в цикле while продолжается до техпор, пока логическое выражение истинно. Он имеетследующий формат:

while <Условие> :    <Инструкции>     [else:

    <Блок,выполняемый, если не использовался оператор break>

]

Последовательностьработы цикла while следующая. Инструкции внутри цикла выполняются пока условиеистинно. При этом истинностьусловия проверяется перед каждой итерацией цикла. Выход из циклаосуществляется либо если условиене прошло очередную проверку на истинность,что может случиться и навходе в цикл, либоесли встречается оператор break. 

Опциональноможно дополнить цикл while, блоком else, инструкции вкотором выполнятся по завершениицикла, при условии, что несработал оператор break.

В отличии от циклаfor, единственнаявозможность которого пробежаться по итерируемомуобъекту, цикл while позволяет писать циклы, выход из которыхосуществляется при более сложных обстоятельствах.  

В качестве примера, рассмотрим поиск наибольшего общего знаменателя методом Эвклида, итерации которого выполняются до техпор, пока наименьшее из чиселне равно нулю.

x, y = 60, 48while y:

    x, y = y, x% y print(x) #вывод 12

Нередко цикл while комбинируют с счетчиком.Тогда он принимает следующий формат:

<3аданиеначального значения для переменной — счетчика> while <Условие> :

   <Инструкции>

   <Приращение значения в переменной — счетчике> [else:

    <Блок,выполняемый, если не использовался оператор break>

]

Последовательность егоработы сводится к:

1.     Переменнойсчетчику присваивается начальное значение.

2.     Проверяется условие, если оно истинно,то выполняются инструкции внутри цикла, иначе выполнение цикла завершается.

3.     Переменнаясчетчик изменяется на величину,указанную в параметре <приращение>.

4.     Переход к пункту 2.

5.     Если внутри цикла не использовалсяоператор break,то после завершения выполнения цикла будет выполнен блок винструкции else. Этот блок не являетсяобязательным.

Создадимпустой список и заполнимего в цикле случайными числами:

import random #модуль генерации случайных чисел  c = [] i = 0 while i < 10:

    c.append(random.randint(0,100))     i += 1 print(c)

Оператор continueпозволяет перейти к следующейитерации цикла до завершениявыполнения всех инструкций внутри цикла. В качествепримера выведем все числаот 1 до 100, кроме чисел от 5 до10 включительно:

for i in range(1,101):     if 4 < i < 11 :

      continue # Переходим на следующую итерацию цикла    print(i)

Оператор break позволяет прервать выполнение цикла досрочно. Для примеравыведем все числа от 1 до100 еще одним способом:

i = 1 whileTrue:    if i > 100:  break  # Прерываем цикл    print(i)     i += 1

Цикл whileсовместно с оператором break удобно использовать для получениянеопределенного заранее количества данных от пользователя.В качестве примера просуммируем произвольное количество чисел:

   

print(Введите слово stop  для получения результата)  summa = 0  while True:

   x = input(Введите число: )     if x == stop:

      break  # Выход из цикла

   x = int(x)  # Преобразуем строку в число    summa += x

print(Сумма чиселравна:,  summa)

 

                  8.         Функции

Функция в программировании представляет собой обособленный участок кода, которыйможно вызывать, обратившись к немупо имени, которым он былназван. При вызове происходит выполнение команд тела функции

Функции можно сравнить с небольшимипрограммками, которые сами посебе, то есть автономно,не исполняются, а встраиваютсяв обычную программу. Нередко их таки называютподпрограммы. Других ключевых отличий функций от программнет. Функции также при необходимостимогут получать и возвращатьданные. Только обычно они ихполучают не с ввода(клавиатуры, файла и др.),а из вызывающей программы. Сюда же онивозвращают результат своей работы.

Существует множество встроенных в языкпрограммирования функций. С некоторымитакими в Python мы уже сталкивались.Это print(),input(), int(), float(), str(), type(). Код ихтела нам не виден,он гдето спрятанвнутри языка. Нам же предоставляетсятолько интерфейсимя функции

С другой стороны, программист всегда может определять свои функции.Их называют пользовательскими.

В языке программирования Python функции определяются с помощьюоператора def

Рассмотрим код: def count_food():     a = int(input())    b = int(input())

    print(Всего, a+b, шт.)

Это пример определения функции. Как идругие сложные инструкции вроде условного оператора и цикловфункция состоит из заголовкаи тела. Заголовок оканчивается двоеточием и переходомна новую строку. Тело имеет отступ.

Ключевое слово def сообщает интерпретатору, что передним определение функции. За def следует имяфункции. Оно может быть любым,так же, как ивсякий идентификатор. В программированиивесьма желательно давать всему осмысленные имена. Так вданном случае функция названа посчитать_еду впереводе на русский. После имени функции ставятся скобки. В приведенномпримере они пустые. Это значит,что функция не принимаетникакие данные из вызывающейее программы. Однако она моглабы их принимать, и тогдав скобках были быуказаны параметры этой функции

После двоеточия следует тело, содержащееинструкции, которые выполняются при вызовефункции. Следует различать определение функции и еевызов. В программном коде онине рядом и невместе. Можно определить функцию, но ниразу ее не вызвать.Нельзя вызвать функцию, которая не былаопределена. Определив функцию, но ниразу не вызвав ее, выникогда не выполните ее тела.

   

def count_food():     a = int(input())     b = int(input())     print(Всего, a+b, шт.)

print(Сколько бананов иананасов для обезьян?) count_food() print(Сколько жуков и червей для ежей?) count_food() print(Сколько рыб имоллюсков для выдр?)count_food() 

В языке Python определение функции должно предшествовать ее вызовам.Это связано с тем,что интерпретатор читает код строказа строкой и отом, что находится ниже потечению, ему еще неизвестно.Поэтому если вызов функции предшествует ее определению,то возникает ошибка (выбрасывается исключение NameError ).

Польза функций не тольков возможности многократного вызова одного и тогоже кода из разныхмест программы. Не менееважно, что благодаря им программаобретает истинную структуру. Функции как быразделяют ее на обособленныечасти, каждая из которыхвыполняет свою конкретную задачу.

Функции могут передавать какиелибо данныеиз своих тел восновную ветку программы. Говорят, что функциявозвращает значение. В большинствеязыков программирования, в томчисле Python, выход из функциии передача данных в томесто, откуда она былавызвана, выполняется оператором return .

Если интерпретатор Питона, выполняя тело функции,встречает return, то он забирает значение, указанное после этой команды,и уходит из функции.

def cylinder():

    r = float(input())     h = float(input())

    # площадь боковойповерхности цилиндра:    side = 2 * 3.14 * r * h

    # площадь одногооснования цилиндра:    circle = 3.14 * r**2     # полная площадь цилиндра:     full = side + 2 * circle     return full square = cylinder() print(square)

В Питоне позволительно возвращать из функциинесколько объектов, перечислив их череззапятую после команды return:

def cylinder():

    r = float(input())     h = float(input())     side = 2 * 3.14 * r *h     circle = 3.14 * r**2     full = side + 2 * circle     return side, full sCyl, fCyl = cylinder()

print(Площадь боковойповерхности %.2f %sCyl) print(Полнаяплощадь %.2f %fCyl)

Из функции cylinder() возвращаются два значения.Первое из них присваиваетсяпеременной sCyl,второеfCyl.

Фокус здесь в том,что перечисление значений через запятую (например, 10, 15, 19) создает объект типа tuple. Нарусский переводится как кортеж.Когда же кортеж присваивается сразу нескольким переменным, то происходитсопоставление его элементов соответствующим в очередипеременным. Это называется распаковкой.

Таким образом, когда из функциивозвращается несколько значений, на самомделе из нее возвращаетсяодин объект класса tuple. Перед возвратом эти несколькозначений упаковываются в кортеж.Если же после оператора return стоит только одна переменнаяили объект, то ее/его тип сохраняетсякак есть.

Функции могут не тольковозвращать данные, но такжепринимать их, что реализуетсяс помощью так называемыхпараметров, которые указываются в скобкахв заголовке функции. Количество параметров может быть любым.

Параметры представляют собой локальные переменные, которым присваиваются значения в моментвызова функции. Конкретные значения, которые передаются в функциюпри ее вызове, называются аргументами.

Когда функция вызывается, то ейпередаются фактические значения аргументов. Т.е.переменнымпараметрам присваиваются переданные в функциюзначения. Соответственно, изменение значений в телефункции никак не скажетсяна значениях фактических переменных. Они останутсяпрежними. В Python такое поведение характерно для неизменяемыхтипов данных, к которымотносятся, например, числа и строки

Существуютизменяемые типы данных. Для Питона,это, например, списки и словари.В этом случае данные передаются по ссылке.В функцию передается ссылка на них,а не сами данные.И эта ссылка связывается с локальнойпеременной. Изменения таких данных через локальную переменную обнаруживаются при обращениик ним через глобальную. Это естьследствие того, что несколькопеременных ссылаются на однии те же данные,на одну и туже область памяти. Необходимость передачи по ссылкесвязана в первую очередь с экономиейпамяти. Сложные типы данных,по сути представляющие собой структуры данных, обычно копировать не целесообразно.Однако, если надо, всегдаможно сделать это принудительно.

                  9.        Модули

Встроенныев язык программирования функции доступны сразу. Чтобы их вызвать,не надо выполнять никаких дополнительных действий. Однако за времясуществования языка на нембыло написано столько функций и классов,которые оказались востребованными множеством программистов и вразных областях, что включитьвесь этот объем кода всам язык если возможно,то нецелесообразно

Чтобы разрешить проблему доступа к дополнительнымвозможностям языка, в программированиистало общепринятой практикой использовать так называемыемодули, пакеты и библиотеки.Каждый модуль содержит коллекцию функций и классов,предназначенных для решения задач из определеннойобласти. Так в модулеmath  языка Python содержатся математические функции, модуль random  позволяет генерировать псевдослучайные числа, в модулеdatetime  содержатся классы для работыс датами и временем,модуль  sys предоставляет доступ к системнымпеременным и т. д.

Количествомодулей для языка Python огромно, что связанос популярностью языка. Часть модулей собрана в такназываемую стандартную библиотеку. Стандартная она потому,что поставляется вместе с установочнымпакетом. Однако существуют сторонние библиотеки. Они скачиваютсяи устанавливаются отдельно.

Для доступа к функционалумодуля, его надо импортироватьв программу. После импорта интерпретатор знает о существовании дополнительных классов и функцийи позволяет ими пользоваться

В Питоне импорт осуществляется командой import . При этом существуетнесколько способов импорта. Рассмотрим работу с модулемна примере math: import math

Вглобальной области видимости появилось имя  math . Еслибы до импорта вы упомянулибы имя math , то возникла бы ошибкаNameError . Теперь же в программезавелся объект math , относящийся к классуmodule . 

Чтобы вызвать функцию из модуля,надо впереди написать имя модуля,поставить точку, далее указать имя функции,после чего в скобкахпередать аргументы, если они требуются.Например, чтобы вызвать функцию pow  из math , надо написать так: print(math.pow(2, 2)) # 4.0

Для обращения к константескобки не нужны:  print(math.pi) # 3.141592653589793

Описание модулей и ихсодержания можно посмотреть в официальнойдокументации на сайте python.org.

Второй способ импорта позволяет импортировать не весьмодуль, а только необходимые функции из него:from math import gcd,sqrt, hypot

Перевести можно как измодуля math  импортировать функции gcd , sqrt  и hypot . В таком случае при ихвызове не надо передименем функции указывать имя модуля:

from math import gcd,sqrt, hypot print(gcd(100, 150)) # 50 print(sqrt(16))      # 4.0 print(hypot(3, 4))   # 5.0

Чтобы импортировать сразу все функциииз модуля: from math import *

Импорт через from  не лишен недостатка. В программеуже может быть идентификаторс таким же именем,как имя одной из импортируемыхфункций или констант. Ошибки не будет,но одно из нихокажется затерто:

pi = 3.14 print(pi) # 3.14 from math import pi print(pi)  # 3.141592653589793

Здесь исчезает значение 3.14, присвоенное переменной pi. Это имя теперьуказывает на число из модуляmath. 

В этой связи более опасен именно импорт всех функций.Так как в этомслучае очень легко не заметитьподмены значений идентификаторов. Однако можно изменить имя идентификатораиз модуля на какоеугодно:

pi = 3.14

from math import pi as P print(P)  # 3.141592653589793 print(pi) # 3.14

В данном случае константа pi из модуля импортируется под именемP. Смысл подобных импортов в сокращенииимен, так как естьмодули с длинными именами, а именафункций и классов в нихеще длиннее. Если в программуимпортируется всего пара сущностей,и они используются в нейчасто, то имеет смысл переименовать их наболее короткий вариант

Сравните:

import calendar print(calendar.weekheader(2))# Mo Tu WeTh Fr Sa Su и

from calendar importweekheader as week print(week(3))  # Mon Tue Wed Thu FriSat Sun

Во всех остальных случаях лучше оставлять идентификаторы содержимого модуля в  пространствеимен самого модуля и получатьдоступ к ним черезимя модуля, то естьвыполнять импорт командой import имя_модуля, а вызывать,например, функции через  имя_модуля.имя_функции().

10. Объектноориентированное программирование

Итак, что же такоеобъектноориентированное программирование? Судя по названию,ключевую роль здесь играют некие объекты, на которыеориентируется весь процесс программирования

Реальный мир для наспредставляется в виде множестваобъектов, обладающих определенными свойствами, взаимодействующих между собой и вследствиеэтого изменяющимися. Эта привычнаядля взгляда человека картина мира былаперенесена в программирование

Ключевую разницу между программой, написанной в структурномстиле, и объектноориентированной можно выразить так. Впервом случае, на первыйплан выходит логика, понимание последовательности выполнения действий для достиженияпоставленной цели. Во второмважнее представить программу как системуобъектов, взаимодействие которых способно решить ту илииную задачу.

Объектноориентированное программированиеэто способ организации программы, позволяющий использовать один итот же код многократно.В отличие от функцийи модулей, ООП позволяетне только разделить программу на фрагменты,но и описать предметы реального мира ввиде удобных сущностейобъектов, а такжеорганизовать связи между этими объектами.

Основным «кирпичиком» ООП являетсякласссложный тип данных,включающий набор переменных и функцийдля управления значениями, хранящимися в этихпеременных

Переменныеназывают атрибутами или свойствами,а функцииметодами. Класс является фабрикой объектов, т. е.позволяет создать неограниченное количество экземпляров, основанных на этомклассе.

Основными понятиями, используемыми в ООП,являются класс, объект, наследование, инкапсуляция и полиморфизм.В языке Python класс равносилен понятию тип данных.

Что такое класс или тип?Проведем аналогию с реальныммиром. Если мы возьмемконкретный стол, то этообъект, но не класс.А вот общее представление о столах,их назначенииэто класс. Ему принадлежатвсе реальные объекты столов, какими бы онини были. Класс столов дает общуюхарактеристику всем столам в мире,он их обобщает.

То же самое с целымичислами в Python. Тип intэто класс целых чисел. Числа 5, 100134, -10 и т. д.– это конкретные объекты этого класса

В языке программирования Python объекты класса принято называть также экземплярами. Это связанос тем, что внем все классы сами являютсяобъектами класса type. Точно также как всемодули являются объектами класса module

Следующее по важности понятие объектноориентированного программированиянаследование. Вернемся к столам.Пусть есть класс столов, описывающий общие свойства всех столов.Однако можно разделить все столына письменные, обеденные и журнальныеи для каждой группы создать свой класс,который будет наследником общего класса, но такжевносить ряд своих особенностей. Таким образом, общий класс будет родительским, а классыгруппдочерними, производными

Дочерние классы наследуют особенности родительских, однако дополняют или вопределенной степени модифицируют их характеристики.Когда мы создаем конкретный экземпляр стола, то должнывыбрать, какому классу столов он будетпринадлежать. Если он принадлежитклассу журнальных столов, то получитвсе характеристики общего класса столов и классажурнальных столов. Но неособенности письменных и обеденных.

Основное (но не единственное)преимущество, которое дает концепциянаследования в программировании, – это вынос одинакового кода изразных классов в одинродительский класс. Другими словами, наследование позволяет сводить на нетповторение кода в разныхчастях программы.

Инкапсуляцияв ООП понимается двояко. Во многихязыках этот термин обозначает сокрытие данных, то естьневозможность напрямую получить доступ к внутреннейструктуре объекта, так какэто небезопасно. Например, наполнить желудок едой можнонапрямую, положив еду вжелудок. Но это опасно.Поэтому прямой доступ к желудкузакрыт. Чтобы наполнить его едой,надо совершить ритуал, через элемент интерфейса под названиемрот.

В Python нет такой инкапсуляции, хотя она являетсяодним из стандартов ООП. ВPython можно получить доступ к любомуатрибуту объекта и изменитьего. Однако есть механизм,позволяющий имитировать сокрытие данных, если это такуж необходимо.

Отсутствиесокрытия данных в Python делаетпрограммирование на нем проще,но привносит ряд особенностей,связанных с пространствами имен

Второй смысл инкапсуляцииобъединение описания свойств объектов и ихповедения в единое целое, то естьв класс. Инкапсуляция в этомсмысле вытекает из самойидеи объектноориентированного программирования и, соответственно,имеется во всех ООязыках.

Полиморфизмможно перевести как множествоформ. В ООП подполиморфизмом понимается следующее. Объекты разных классов, с разнойвнутренней реализацией, то естьпрограммным кодом, могут иметь одинаковые методы. На самомделе у методов совпадают только имена, а вложенныйв них код (то,что они делают) различен. Вот иполучается, что у одногоимени как бы множествоформ.

Например, для чисел есть операциясложения, обозначаемая знаком +. Однако мы можемопределить класс, объекты которого также будут поддерживать операцию, обозначаемую этим знаком.Но это вовсе не значит,что объекты должны быть числами,и будет получаться какаято сумма.Операция + для объектов нашего класса может значить чтотоиное. Но интерфейс, в данномслучае это знак +, учисел и нашего класса будет одинаков. А полиморфизмпроявляется во внутренней реализации и результатеоперации.

Полиморфизмполезен не только тем, чтодает возможность объектам пользовательских классов участвовать в стандартныхоперациях. Если у объектовразных классов есть одноименныйметод, то коллекция таких разнородных объектов может быть обработанав одном цикле.

11. Создание классов и объектов

Классописывается с помощью ключевого слова class по следующей схеме:

class <Названиекласса>[(<Класс1>, …, <Класс№>)]:

    Строка документирования  

   <Описание атрибутов и методов>

Инструкциясоздает новый объект и присваиваетссылку на него идентификатору,указанному после ключевого слова class. Это означает, что названиекласса должно полностью соответствовать правилам именования переменных. После названия класса в круглыхскобках можно указать один илинесколько базовых классов через запятую. Если же классне наследует базовые классы, то круглыескобки можно не указывать.Следует заметить, что всевыражения внутри инструкции class выполняются при созданиикласса, а не егоэкземпляра. Для примера создадим класс, внутри которого просто выводится сообщение:

class MyClass:

    Этострока документирования       print(Инструкции выполняются сразу)

Этотпример содержит лишь определениекласса Myclass и не создаетэкземпляр класса. Как толькопоток выполнения достигнет инструкции class, сообщение, указанное в функцииprint(), будет сразу выведено.

С точки зрения пространства имен классможно представить подобным модулю. Также как вмодуле в классе могут быть своипеременные со значениями и функции.Также как в модулеу класса есть собственноепространство имен, доступ к которомувозможен через имя класса:

class B:     n = 5      def adder(v):

       return v + B.n print(B.n) # Вывод: 5 print(B.adder(4))# Вывод: 9

Однако в случае классов используется особая терминология. Имена, определенные в классе,называются атрибутами этого класса. В примереимена n и adderэто атрибуты класса B. Атрибутыпеременные называют полями или свойствами(в других языках понятия поле и свойство не совсем одно ито же). Полем является n. Атрибутыфункции называются методами. Методом в классеB является adder.Количество свойств и методовв классе может быть любым.

Создание атрибута класса аналогично созданию обычной переменной. Метод внутри класса создается так же,как и обычная функция, – с помощьюинструкции def.Среди атрибутов можно выделить две группы

Атрибуты первой группы принадлежат самому классу, а неконкретному экземпляру. Доступ к такиматрибутам вне тела классаосуществляется через точечную нотацию через объект объявления класса.

<Имякласса>.<Имя атрибута>

Еслиэтот атрибутметод, то поаналогии можно его вызвать.

<Имякласса>.<Имя метода>([<Параметры>])

Во второй группе находятся атрибуты, принадлежащие конкретному экземпляру. В отличииот многих других языков программирования, эти атрибутысоздаются уже во времясуществования объекта. Чтобы создать экземпляр класса используется синтаксис

<экземпляркласса> = <Название класса>([<Параметры>])

Когда экземпляр класса существует, можно задавать атрибуты уникальные для этогосамого экземпляра:

<экземпляркласса>.<Имя атрибута> = <Значение>

Ипо аналогии получать доступ к ужесуществующим атрибутам:

<экземпляркласса>.<Имя атрибута>

При этом если неудается найти атрибут с такимименем у экземпляра, то поискпродолжается в атрибутах, принадлежащих классу. В связис этим можно считать, что атрибутысамого класса разделяются между всеми его экземплярами.

   

class MyClass:

    x =50          #Создаем атрибут объекта класса MyClass

 

c1, с2 = MyClass(), MyClass() # Создаем два экземпляра класса c1.y = 10           # Создаем атрибутэкземпляра класса c1 с2.у= 20           #Создаем атрибут экземпляра класса c2 print(c1.x, ,c1.y) #Вывод: 50 10 print(с2.x, , с2.у) # Вывод: 50 20

В этом примере мы определяемкласс MyClass и создаем атрибут объекта класса: х. Этотатрибут будет доступен всем создаваемымэкземплярам класса. Затем создаем два экземпляракласса и добавляем одноименные атрибуты: у. Значенияэтих атрибутов будут разными в каждомэкземпляре класса. Но еслисоздать новый экземпляр (например, сЗ), тоатрибут у в немопределен не будет. Таким образом, с помощьюклассов можно имитировать типы данных,поддерживаемые другими языками программирования

(например, тип struct, доступный в языкеС).

Обычно все методы класса объявляются на уровнекласса, а не экземпляра.Вызов такого метода через экземпляр класса с помощьюсинтаксиса

<экземпляркласса>.<Имя метода>([<Параметры>]) неявно преобразуется к 

<Имякласса>.<Имя метода>(<экземпляр класса>, [<параметры>])

Иными словами, методам класса в первомпараметре, который необходимо указывать явно, автоматическипередается ссылка на экземпляркласса. Общепринято этот параметрназывать именем self, хотя это ине обязательно. Доступ к атрибутами методам класса внутри определяемого метода производится через переменную self с помощью точечной нотации. Обратите внимание на то,что при вызове метода не нужнопередавать ссылку на экземпляркласса в качестве параметра, как этоделается в определении метода внутри класса. Ссылку на экземпляркласса интерпретатор передает автоматически.

Определим класс MyСlass с атрибутомх и методом print_x(), выводящим значение этого атрибута, а затемсоздадим экземпляр класса и вызовемметод:

class MyClass:

   def __init__(self):  # Конструктор

      self.x = 1        # Атрибут экземпляракласса    def print_x(self):   #  self — это ссылка на экземпляр класса       print(self.х)     # Выводим значение атрибута с = MyClass()           # Создание экземпляра класса

#Вызываем метод print_x()

c.print_x()  # self не указываетсяпри вызове методаprint(с.х)   #К атрибуту можно обратиться непосредственно

Все атрибуты класса в языкеPython являются открытыми (public), т. е. доступнымидля непосредственного изменения как изсамого класса, так ииз других классов и изосновного кода программы.

Очень важно понимать разницу между атрибутами объекта класса и атрибутамиэкземпляра класса. Атрибут объекта класса существует в единственномэкземпляре, доступен всем экземплярамкласса, его изменение можно видеть во всехэкземплярах класса. Атрибут экземпляра класса хранит уникальное значение для каждогоэкземпляра, и изменение его водном экземпляре класса не затронетзначения одноименного атрибута в другихэкземплярах того же класса.Рассмотрим это на примере,создав класс с атрибутомобъекта класса (х) иатрибутом экземпляра класса (у): 

   

class MyClass:

   х = 10  # Атрибут объекта классаобщий для всех экземпляров    def __init__(self):

      self.y = 20   # Атрибут экземпляракласса уникальный для каждого экземпляра c1 = MyClass() # Создаем первый экземпляр классас2 = MyClass()  # Создаем  второй экземпляр класса

Представленная информация была полезной?
ДА
58.55%
НЕТ
41.45%
Проголосовало: 982

#Выведемзначения атрибута х, а затем изменим значение и опять произведем вывод: print (c1.x,  с2.х)  # Вывод: 10  10

MyClass.х = 88       # Изменяем атрибутобъекта (класса MyClass)print (c1.x,  с2.х)  # Вывод: 88  88 print (c1.у,  с2.у)  # Вывод: 20 20

cl.y = 88  # Изменяем атрибутэкземпляра класса с1

print (c1.y, с2.у)  #Вывод: 88 20

Как видно из примера,изменение атрибута объекта класса x затронуло значение в обоихэкземплярах класса. Аналогичная операция с атрибутому изменяет значение только в экземпляреc1.

Следует также учитывать, что водном классе могут одновременно существовать атрибут объекта и атрибутэкземпляра с одним именем. Изменение атрибута объекта класса мы производилиследующим образом:

MyClass.х = 88 # Изменяем атрибутобъекта класса

Еслипосле этой инструкции вставить инструкцию:

cl.x = 200  # Создаем атрибутэкземпляра

тобудет создан атрибут экземпляра класса, а неизменено значение атрибута объекта класса. Чтобы увидеть разницу, нужно вывести их значения:

print (cl.x,MyClass.х)  #200 88

Метод __init__()

При создании экземпляра класса интерпретатор автоматически вызывает метод инициализации __init__(). Такой метод принято называть конструктором класса. Формат метода:

def  __init__(self[, <3начение1>[,  . ..,  <ЗначениеN>]]):

    <Инструкции>

С помощью метода __init__() атрибутам класса можно присвоить начальные значения.

При создании экземпляра класса параметры этого метода указываются после имени класса в круглыхскобках:

<Экземпляр класса> = <Имякласса> ([<3начение1> [,  …,<ЗначениеN>]]) Пример использования метода:

class MyClass:

   def__init__(selfvaluelvalue2):  #  Конструктор       self.x = valuel       self.у = value2

c = MyClass(100,  300)  # Создаем экземпляркласса print(с.x,  с.у)  #  Вывод:  100  300  

Метод __del__()

Перед уничтожением экземпляра автоматически вызывается метод, называемый деструктором. В языкеPython деструктор реализуется в видепредопределенного метода__del__() (листинг 13.6). Следует заметить, что методне будет вызван, если на экземпляркласса существует хотя быодна ссылка

Впрочем, поскольку интерпретатор самостоятельно заботится об удаленииобъектов, использование деструктора в языкеPython не имеет особого смысла.

12. Наследование

Наследованиеявляется, пожалуй, самым главным понятием ООП

Предположим,у нас есть класс(например, Class1). При помощи наследования мы можемсоздать новый класс (например, Class2), в котором будет реализован доступ ко всематрибутам и методам класса Сlass1:

class Class1:            # Базовый класс    def funс1(self):       print(Метод  funс1() класса  Class1)    def func2(self) :

      print(Метод func2() класса Class1)

 class Class2(Classl):  

#Класс Class2 наследует класс Classl     def func3(self):

      print(Метод func3() класса Class2

 

c = Class2()   # Создаем экземпляр класса Class2

c.funс1()      # Выведет: Метод  funcl()класса  Classl

c.func2()      # Выведет: Метод func2() класса  Classl

c.func3()      # Выведет: Метод func3() класса  Class2

Как видно из примера,класс Classl указывается внутри круглых скобок в определениикласса Class2. Таким образом, класс Class2 наследует все атрибутыи методы класса Classl

Класс Classlназывается базовым или суперклассом,а класс Class2производным или подклассом.

Если имя метода в классеClass2 совпадаетс именем метода класса Classl, то будет использоваться метод из классаClass2. Чтобы вызвать одноименный метод из базовогокласса, перед методом следует через точку написать название базового класса, а впервом параметре методаявно указать ссылку на экземпляркласса. Рассмотрим это напримере

class Class1:   #  Базовый класс    def __init__( self ):

      print(Конструкторбазового класса)    def funс1(self):

      print (Метод funс1() класса Class1)

 class Class2(Class1):  

# Класс Class2 наследует класс Classl    def __init__(self ):

      print(Конструкторпроизводного класса

      Class1.__init__(self# Вызываем конструктор базового класса    def funс1(self):

      print (Метод func1()класса Class2)

      Class1.funс1(self# Вызываем метод базового класса

 с = Class2()  # Создаем экземпляр класса Class2

с.funс1()     # Вызываем метод funс1()

 

Вывод:

Конструкторпроизводного класса  Конструктор базового класса 

Метод func1()класса Class2 

Метод func1()класса Classl

 

Обратите внимание, что конструкторбазового класса автоматически не вызывается,если он переопределен в производномклассе. Поэтому его нужновызывать явно либо так,как в приведенном примере, либо используя метод super():

super().__init__()  

#Вызываем конструктор базового класса

илитак:

super(Class2,  self).__init__()  

#Вызываем конструктор базового класса

При использовании функции super()  не нужно явно передаватьуказатель  self  в вызываемый метод. Кроме того, впервом параметре функции super() указывается производный класс, а небазовый

13. Множественное наследование

В определении класса в круглыхскобках можно указать сразу несколько базовых классов через запятую. Рассмотрим пример

class Classl:          

#Базовый класс для класса Class2    def func1(self):

      print (Метод funс1() класса Classl) class Class2(Classl):  

#Класс Class2 наследует класс Classl     def func2(self):

      print(Метод func2() класса Class2) class Class3(Classl):  

#Класс Class3 наследует класс Classl     def func1(self):

      print(Метод funс1() класса Class3)     def func2(self):       print(Метод func2()  класса Class3)     def func3(self):      print(Методfunc3()  класса Class3)    def func4(self):

      print(Метод func4() класса Class3) class Class4(Class2Class3):   # Множественное наследование     def func4(self):

      print( Метод func4() класса Class4)  c =Class4()  # Создаем экземпляр класса Class4

c.func1()  #  Вывод: Метод  func1()класса  Class3

c.func2()  #  Вывод: Метод  func2()класса  Class2

c.func3()  #  Вывод: Метод  func3()класса  Class3

c.func4()  #  Вывод: Метод  func4()класса  Class4  

Метод funс1() определен в двухклассах: Class1и Class3. Так как вначалепросматриваются все базовые классы, непосредственно указанные в определениитекущего класса, то методfunс1() будет найден в классеClass3 (посколькуон указан в числебазовых классов в определенииClass4), а не в классеClassl.

Метод func2()также определен в двухклассах: Class2и Class3Так как классClass2 стоит первым в спискебазовых классов, то методбудет найден именно в нем.Чтобы наследовать метод из классаClass3, следуетуказать это явным образом:

class Class4(Class2,  Class3):   # Множественное наследование

   func2 = Class3.func2 # Наследуем func2()  из класса Class3,  ане из класса Class2     def  func4(self):       print(Метод func4()  класса Class4)

14. Перегрузка операторов

Перегрузкаоператоров позволяет экземплярам классов участвовать в обычныхоперациях

Чтобы перегрузить оператор, необходимо в классеопределить метод со специальнымназванием. В результате, для выполнениядействия соответствующего данной операции будет вызываться этот метод.

Перегрузкаматематических операторов производится с помощьюследующих методов:

Выражение

Операция

Метод

x+y

сложение

x.__add__(у)

y+x

сложение (экземпляр класса справа)

х .__radd__(у)

x+=y

сложение и присваивание

х.__iadd__(у)

x-y

вычитание

х.__sub__(у)

y-x

вычитание (экземпляр класса справа

х.__rsub__(у)

x-=y

вычитание и присваивание

х.__isub__(у)

x*y

умножение

x.__mul__(у)

y*x

умножение (экземпляр класса справа):

х.__rmul__(у)

x*=y

умножение и присваивание

х .__imul__(у)

x@y

матричное умножение

x.__matmul__(y)

y@x

матричное умножение (экземпляр класса справа

x.__rmatmul__(y)

x@=y

Матричное умножение и присваивание

x.__imatmul__(y)

x/y

деление

x.__truediv__(у

y/x

деление (экземпляр класса справа):)

х.__rtruediv__(у

x/=y

деление и присваивание

x.__itruediv__(у)

x//y

деление с округлением вниз

x.__floordiv__(у)

y/=x

деление с округлением вниз (экз. класса справа):

х.__rfloordiv __(у)

x/=y

деление с округлением вниз и присваивание

x.__ifloordiv __(у)

x%y

остаток от деления

х.__mod__(у)

y%x

остаток от деления (экземпляр класса справа):

х.__rmod__(у)

x%=y

остаток от деления и присваивание

х.__imod__(у)

x**y

возведение в степень

x.__pow__(у)

y**x

возведение в степень (экземпляр класса справа):

х.__rpow__(у)

x**=y

возведение в степень и присваивание

х.__ipow__(у)

-x

унарный минус

х.__neg__()

+x

унарный плюс

х.__pos__()

abs(x)

абсолютное значение

х.__abs__().

 

Примерперегрузки математических операторов:

class MyClass:    def __init__(self,у):       self.x= у    def __add__(self,y):       print( Экземпляр слева)        return self.x + y    def __radd__(self,y):       print( Экземпляр  справа)        return self.x + y    def __iadd__(self,y):

      print( Сложение  с присваиванием)       self.x += y        return self   c  =  MyClass(50)

print( c + 10 ) #  Вывод:  Экземпляр слева  60 print( 20 + c )#  Вывод: Экземпляр  справа  70 c+= 30         # Вывод:  Сложение  с  присваиванием print( c.x )    #  Вывод:  80

 

Перегрузка операторов сравнения производится с помощьюследующих методов:

   

Выражение

Операция

Метод

x==y

равно

x.__eq__(у)

x!=y

не равно

х .__ne__(у)

x<y

меньше

х.__lt__(у)

x>y

больше

х.__gt__(у)

y<=x

меньше или равно

х.__le__(у)

x>=y

больше или равно

х.__ge__(у)

x in y

проверка на вхождение

x.__ contains__(у)

 

Примерперегрузки операторов сравнения:

class  MyClass:    def __init__(self):

      self.x = 50

      self.arr   =  [1,  2,  3,  4,  5]

   def  __eq__(self, y ):  #  Перегрузка  оператора  ==       return self.x == y

   def __contains__(self,у) :  #  Перегрузка  оператора  in       return у in self.arr   c  =  MyClass ()

print(Равно  if c  ==  50  else  He  равно#  Вывод:  Равно  print(Равно  if c  ==  51 else  He  равно#  Вывод:  He  равно  print(Есть if 5 in c else  Нет# Вывод:  Есть

Возможностьперегрузки операторов обеспечивает схожесть пользовательского класса со встроеннымиклассами Python. Ведь все встроенныетипы данных Питонаэто классы. В результатевсе объекты могут иметь одинаковые интерфейсы. Так есливаш класс предполагает обращение к элементуобъекта по индексу, например a[0], то это нужнообеспечить.

Пустьбудет классагрегат B, содержащий в спискеобъекты класса A:

class A:    def __init__(self, arg):

      self.arg = arg    def __str__(self):

      return str(self.arg) class B:

   def__init__(self, *args):

      self.aList = []       for i in args:          self.aList.append(A(i))  group = B(5, 10, abc)

Чтобы получить элемент списка, несомненно, мы можемобратиться по индексу к полюaList: print(group.aList[1])

Однако куда интереснее извлекать элемент по индексуиз самого объекта, а неиз его поля:

   

class B:

    def__init__(self, *args):

        self.aList = []         for i in args:

            self.aList.append(A(i))     def__getitem__(self, i):         return self.aList[i] group =B(5, 10, abc) print(group.aList[1])  # вывод: 10 print(group[0])  # 5 print(group[2])  # abc

Это делает объекты класса B похожими на объектывстроенных в Python классовпоследовательностей (списков, строк, кортежей). Здесь метод __getitem__() перегружает операцию извлечения элемента по индексу.Другими словами, этот метод вызывается, когда к объектуприменяется операция извлечения элемента: объект[индекс].

Бывает необходимо, чтобы объект вел себякак функция. Это значит,если у нас естьобъект a,то мы можем обращаться к немув нотации функции, т. е.ставить после него круглыескобки и даже передаватьв них аргументы:

a = A() a()a(3, 4)

Метод __call__()автоматически вызывается, когда к объектуобращаются как к функции

classChangeable:

    def__init__(self, color):

        self.color = color     def __call__(self, newcolor):

        self.color = newcolor     def __str__(self):

        return %s%self.color canvas = Changeable(green) frame = Changeable(blue) canvas(red) frame(yellow) print(canvas, frame)

В этом примере с помощьюконструктора класса при созданииобъектов устанавливается их цвет.Если требуется его поменять,то достаточно обратиться к объектукак к функции и вкачестве аргумента передать новый цвет. Такойобращение автоматически вызовет метод __call__(), который, в данномслучае, изменит атрибут color объекта.

15. Абстрактные методы

Абстрактные методы содержат только определение метода без реализации.Предполагается, что производный класс должен переопределить метод и реализоватьего функциональность. Чтобы такое предположение сделать более очевидным, часто внутри абстрактного метода возбуждают исключение:

   

class Class1:    def __init__(self,val):

      self.x=val

   def func(self):  # Абстрактный метод

      # Возбуждаем исключение

      raise NotImplementedError(Нельзя вызывать абстрактный методclass Class2(Class1):  # Наследуем абстрактный метод    def func(self):  #  Переопределяем метод        print(self.x) с2 = Class2(10) с2.func()  # Вывод:  10 c1 = Class1(20)

try# Перехватываем исключения

   c1.func()  # Ошибка.  Метод func() не переопределен except NotImplementedError as msg:

   print(msg)  # Вывод:  Нельзявызывать абстрактный метод

 

Модуль стандартной библиотеки abc (аббревиатура от Abstract Base Class) предоставляет дополнительные возможности. Наследуя от классаabc.ABC”, вы явно указываете, что объявляемыйклассабстрактный базовый класс, т.е.создание его экземпляров не предполагается.Такой класс лишь задаётинтерфейс, который должен быть реализованв производных классах. Если хотя быодин из специальным образом помеченных методов абстрактного базового класса не переопределен,то Python бросит ошибку TypeError при попытке создания экземпляра этого классаТакое поведение позволит отловить ошибку на болеераннем этапе, если программист забыл про какойто из абстрактныхметодов.

import abc class Class1(abc.ABC):     def __init__(self, val):

        self.x = val

    @abc.abstractmethod # Абстрактный метод     def func(self):  

        raise NotImplementedError(Нельзя вызывать абстрактный метод

 

class Class2(Class1): # Наследуем абстрактныйметод     def another_func(self): # Определяем другой метод         print(-self.x)

         class Class3(Class2):  # Наследуем два метода

    def func(self):  #  Переопределяем абстрактный метод метод         print(self.x)

 try: # Перехватываем исключения

    c = Class1(10) # Ошибка.  Метод func()  не переопределен except TypeError as msg: 

    print(msg) # вывод: Cantinstantiate abstract class Class1 with abstract …

    

try: # Перехватываем исключения

    c = Class2(10) # Ошибка.  Метод func()  не переопределен except TypeError as msg:

    print(msg) # вывод: Cantinstantiate abstract class Class1 with abstract …

 c = Class3(30)

c.func() # вывод: 30

c.another_func()# вывод:-30

В рассмотренном примере, экземпляры классов Class1 и Class2 невозможно создать, т.к.у обоих из нихесть метод func, помеченный абстрактным с помощьюдекоратора @abc.abstractmethod.Класс Class3 переопределяет этот метод,что позволяет создать его экземпляры.

16. Ограничение доступа к атрибутам класса

В Python нет истинно закрытых атрибутов. Какие бы усилиявы не приложили, пользователь всегда сможет получить доступ к любомуатрибуту вашего класса. По этойпричине в Python обычно отдают предпочтение более простому открытому коду, нежеличем усложненному, который пытается скрыть детали имплементации.

Вместо этого программисты на python стараютсяследовать общепринятого соглашения, что всеидентификаторы, имя которых не начинаетсяс символов нижнего подчеркивания, считаются публичными. Пользователи класса смело могут напрямую обращаться к такимидентификаторам, а разработчики берут на себяответственность сохранять наличие и рольтаких идентификаторов в ближайшихобновлениях. Совокупность таких идентификаторов часто называют интерфейсом класса

Следует обратить внимание, что идентификаторы,имена которых начинаются с двухсимволов нижнего подчеркивания, не виднынапрямую:

class MyClass:    def __init__(self, x):                self.__x = x

                 self.y = x ** 2  a = MyClass(2) print(a.y)   # вывод 4

print(a.__x) # ошибка, объект неимеет атрибута __x

Тем не менее, к нимтоже можно обратиться извне добавив имя классас предшествующим символом подчеркивания: print(a._MyClass__x) # вывод: 2

17. Полиморфизм

В качестве примера предположим, что нужнореализовать приложение с базойданных сотрудников. Имеет смысл начать с созданияуниверсального суперкласса, в которомопределены стандартные линии поведения, общие для всехтипов сотрудников в организации.

class Employee:                        # Универсальный суперкласс сотрудников

    def computeSalary (self) : . . .  # Cтандартный расчетзарплаты

После написания кода общегоповедения можно специализировать его длякаждого индивидуального типа сотрудника,отражая его отличия от нормы.То есть можно создавать подклассы, настраивающие только те фрагментыповедения, которые отличаются в зависимостиот типа сотрудникаостальное поведение будет унаследовано от болееуниверсального класса. Скажем, если с инженерамисвязано уникальное правило подсчета заработной платы, то можнозаменить в подклассе только один метод:

class Engineer(Employee ) :       # Специализированный подкласс инженеров    def computeSalary(self) : …  # Специальный метод расчета зарплаты

Изза того, чтоверсия computeSalaryнаходится ниже в деревеклассов, она заместит (переопределит) универсальную версию в Employee. Теперь можносоздавать экземпляры разновидностей классов сотрудников, к которымпринадлежат реальные сотрудники, чтобы получить корректное поведение:

bob = Employee()  #Стандартное поведение sue=  Employee()  #Стандартное поведение

tom = Engineer()  #Специальный расчет заработной платы

Обратите внимание, что можносоздавать экземпляры любого класса в дереве(за исключением абстрактных), а нетолько классов в нижнейчастикласс, из котороговы создаете экземпляр, определяет уровень, откуда будет начинаться поиск атрибутов, и соответственното, какие версии методов он будетзадействовать. В конце концов, эти объектымогут оказаться встроенными в болеекрупный контейнерный объект (например, список или экземплярдругого класса), который представляет отдел или компанию.Когда нужно будет запросить заработные платы сотрудников, они будутрассчитываться в соответствии с классами,из которых создавались объекты, благодаря принципам поиска в иерархиинаследования:

company = [bob,sue, tom]    #Список сотрудников for emp in company:    print( emp.computeSalary() )  # Метод computeSalary()из соответствующего класса

18. Композиция

Еще одной особенностью объектноориентированного программирования является возможность реализовывать так называемыйкомпозиционный подход. Заключается он втом, что есть классконтейнер, он жеагрегатор, который включает в себявызовы других классов. В результатеполучается, что при созданииобъекта классаконтейнера, также создаются объекты других классов.

Чтобы понять, зачем нужна композиция в программировании,проведем аналогию с реальныммиром. Большинство биологических и техническихобъектов состоят из болеепростых частей, также являющихся объектами. Например, животное состоит из различныхорганов (сердце, желудок), компьютериз различногожелеза (процессор, память). 

Не следует путать композицию с наследованием,в том числе множественным. Наследование предполагает принадлежность к какойто общности (похожесть), а композицияформирование целого из частей.Наследуются атрибуты, т. е.возможности, другого класса, при этом,объектов непосредственно родительского класса не создается.При композиции же классагрегатор создает объекты других классов.

Рассмотримна примере реализацию композиции в Python. Пусть,требуется написать программу, которая вычисляет площадь обоев для оклеиванияпомещения. При этом окна,двери, пол и потолококлеивать не надо

Прежде, чем писать программу, займемся объектноориентированным проектированием. То естьразберемся, что к чему.Комнатаэто прямоугольный параллелепипед, состоящий из шестипрямоугольников. Его площадь представляет собой сумму площадей составляющих его прямоугольников.Площадь прямоугольника равна произведению его длинына ширину.

По условию задачи обои клеятсятолько на стены, следовательно, площади верхнего и нижнегопрямоугольников нам не нужны.Кроме того, надо будет вычесть общую площадь дверей и окон,поскольку они не оклеиваются.

Можно выделить три типаобъектовокна, двери и комнаты.Получается три класса. Окна и двериявляются частями комнаты, поэтому пусть они входятв состав объектапомещения

Для данной задачи существенное значение имеют только два свойствадлина и ширина. Поэтому классы «окна» и «двери»можно объединить в один.Если бы были важныдругие свойства (например, толщина стекла, материал двери), то следовалобы для окон создатьодин класс, а длядверейдругой. Пока обойдемся одним, и всечто нам нужно от негоплощадь объекта:

class WinDoor:    def __init__(self, x, y):       self.square = x * y 

Класскомнатаэто классконтейнер для окони дверей. Он долженсодержать экземпляры класса WinDoor.

Хотя помещение не можетбыть совсем без окони дверей, но можетбыть чуланом, дверь которого также оклеивается обоями. Поэтому имеет смысл в конструкторкласса вынести только размеры самого помещения, без учетаэлементов дизайна, а последние добавлять вызовом специально предназначенного для этогометода, который будет добавлять объектыкомпоненты в список.

class Room:    def __init__(self, x, y, z):

      self.square = 2 * z * (x + y)       self.wd = []    def add_wd(self, w, h):       self.wd.append(WinDoor(w, h))    defwork_surface(self):       new_square = self.square       for i in self.wd:          new_square -=i.square                returnnew_square

#———————————— r1 = Room(6, 3, 2.7) 

print(r1.square)         # вывод:48.6  r1.add_wd(1, 1) r1.add_wd(1, 1)  r1.add_wd(1, 2) 

print(r1.work_surface()) #вывод:44.6

19. Статические методы

Ранее было сказано, с определеннымдопущением классы можно рассматривать как модули,содержащие переменные со значениямии функции. Только здесь переменные называются полями или свойствами,а функцииметодами. Вместе поля иметоды называются атрибутами. Когда метод применяется к объекту,этот экземпляр передается в методв качестве первого аргумента:

class A:    def meth(self):       print(meth)

 a = A()

a.meth()  # для объкта a(экземпляра класса A) вызываем метод meth(a)

A.meth(a) # вызываем методпринадлежащий классу A и передаем ему экземпляр a

Т.еa.meth() на самом деле преобразуетсяк A.meth(a), то есть мыидем к модулю A и в егопространстве имен ищем атрибутmeth. Там оказывается, что meth этофункция, принимающая один обязательныйаргумент. Тогда ничего не мешаетсделать так:

class A:

   def meth(self):       print(meth)

A.meth(10)

В таком модульном формате вызова методов передавать объектэкземпляр именно класса A совсем не обязательно.Что делать, если возникает необходимость в методе,который не принимал бы объектданного класса в качествеаргумента? Да, мы можемобъявить метод вообще без параметрови вызывать его толькочерез класс:

class A:    def meth():

      print(meth)

a = A()

A.meth()  # вызываем метод безпараметров принадлежащий классу A

a.meth()  # Ошибка, в метод безпараметров передается аргумент self

Получаетсястранная ситуация. Ведь meth() вызывается не толькочерез класса, но ичерез порожденные от негообъекты. Однако в последнемслучае всегда будет возникать ошибка. Кроме того, можетпонадобиться метод с параметрами,но которому не надопередавать экземпляр данного класса

Для таких ситуаций предназначены статические методы. Эти методымогут вызываться через объекты данного класса, но самобъект в качестве аргумента в нихне передается. В Python остройнеобходимости в статических методах нет. Еслинам нужна просто какаянибудь функция, мы можемопределить ее вне классаЕдинственное достоинство в том,что функция оказывается в пространствеимен этого класса.

Статическиеметоды в Python реализуются с помощьюспециального декоратора @staticmethod:

class A:    @staticmethod    def meth():

      print(meth)

A.meth()   # вызываем статическийметод (без параметров) принадлежащий классу A a = A()

a.meth()   # вызываем статическийметод без параметров через экземпляр класса A

Вообще, если в телеметода не используется self, то есть ссылкана конкретный объект, следует задуматься, чтобы сделать метод статическим

Пусть у нас будеткласс Цилиндр. При создании объектов от этогокласса у них заводятсяполя высота и диаметр,а также площадь поверхности. Вычисление площади можно поместить в отдельнуюстатическую функцию. Она вродеи относится к цилиндрам,но, с другой стороны, само вычисление объекта не требуети может быть использованогде угодно.

from math import pi class Cylinder:     @staticmethod     def make_area(d, h):         circle = pi * d**2 / 4         side = pi * d * h         return circle*2 + side     def __init__(self, diameter, high):

        self.dia = diameter         self.h = high

        self.area = self.make_area(diameter, high) a = Cylinder(1, 2) print(a.area)

print(a.make_area(2,2))

 

В примере вызов make_area() за пределами класса возможен в томчисле через экземпляр. При этомпонятно, в данном случае свойство area самого объекта a не меняется. Мы простовызываем функцию, находящуюся в пространствеимен класса.

20. Примеры объектноориентированных программ на Python

В ООП очень важно предварительное проектирование. В общейсложности можно выделить следующие этапы разработки объектноориентированной программы:

1.                    Формулирование задачи.

2.                    Определение объектов, участвующих в еерешении.

3.                    Проектирование классов, на основекоторых будут создаваться объекты. В случае необходимости установление между классами наследственных связей.

4.                    Определение ключевых для даннойзадачи свойств и методовобъектов.

5.                    Создание классов, определение их полейи методов.

6.                    Создание объектов.

7.                    Решение задачи путем организации взаимодействия объектов.

Далее приведены примеры классов в порядкевозрастания сложности. Сначала простые классы. Далееклассы демонстриующие наследование, полиморфизм и композицию.

                                        Класс рациональных дробей

Простой класс, представляющий рациональную дробь (numчислитель, denзнаменатель). Класс содержит конструктор и перегруженныеметоды умножения и деления(дроби на дробь и дробина целое число).  Метод создания случайной дроби из заданногодиапазона целых чисел объявлен как статический.

Следует отметить, что вязыке имеется готовый тип Fraction в модулеfractions. И данный пример нужно рассматривать только как образецдля создания собственных классов.

from math import gcd from random importrandint

  class My_Fraction:     def __init__(self, num, den):        if num != 0 and den != 0:

            k =gcd(num, den) # находим НОД             self.num =num // k  # числитель             self.den = den // k  # знасенатель         else:             raise ValueError

                @staticmethod     def generate(num_min, num_max, den_min, den_max):

        return My_Fraction(randint(num_min, num_max), randint(den_min, den_max))

    

    def __str__(self):           # Метод преобразованиядроби в строку         return f{self.num}/{self.den}

    

    def __mul__(self, other):    # Умножение дробей

        if isinstance(other,My_Fraction): # перегрузка умножения на дробь             return My_Fraction(self.num * other.num, self.den *other.den)         if isinstance(other,int):  # перегрузка умножения на целое число             return My_Fraction(self.num *other, self.den)

        return self               # дляостальных типов возвращаем значение самого объекта     

    def __truediv__(self, other): # Деление дробей

        if isinstance(other,My_Fraction):  # перегрузка деления на дробь             return My_Fraction(self.num * other.den,self.den * other.num)         ifisinstance(other,int):  # перегрузка деления на целое число             return My_Fraction(self.num, self.den*other)

        raise TypeError            # для остальных типов вызываем исключение #———————————————————————-

#Список из 5 случайных дробей: a = [My_Fraction.generate(1, 9, 1, 9) for i in range(5)]  for f in a:     b =My_Fraction.generate(1, 9, 1, 9)  # дробь для правогооперанда     cm = f * b

    print(f{f} * {b} = {cm}) # пример умножения на дробь     cd = f / b

    print(f{f} / {b} = {cd}) # пример деления на дробь     n=randint(1, 9)  # число для правогооперанда     cm = f * n

    print(f{f} * {n} = {cm}) # пример умножения на число     cd = f / n

    print(f{f} / {n} = {cd}) # пример деления на число

 

                                         Класс «Студент»

Класс содержит имя студентаfull_name, номергруппы group_numberи список полученных оценок progress. В программе вводится список студентов. Далее список сортируется по имени,потом выводятся студенты, имеющие неудовлетворительные оценки.

class Student

    def __init__(self,full_name=, group_number=0, progress=[]): # конструктор         self.full_name= full_name  # имя

        self.group_number = group_number # номер группы         self.progress = progress   #оценки

    def __str__(self):   # печатаемое представление экземпляракласса         txt = Студент: + self.full_name + Группа: + self.group_number         txt += Оценки:         for x in self.progress:

           txt+= + str(x) # добавляем список оценок         returntxt

#—————————————————————————— def SortParam(st): # функция определяющаяатрибут для сортировки   return st.full_name

#—————————————————————————— st_size = 5  # количество студенов

 

students = [] # создание пустогосписка

for i in range(st_size): # цикл для ввода st_size студентов    print(Введитеполное имя студента: )     full_name = input() # ввод фамилии     print(Введите номер группы: )     group_number = input() # ввод группы     n=5     print(Введите ,n, оценок в столбик: ) # у каждого студента n оценок      progress = []     for i in range(n):

        score =int(input()) # ввод оценок         progress.append(score) # добавление оценок

    # создание экзепляракласса Student:

    st = Student(full_name, group_number,progress)      students.append(st) # добавление экземпляра в список

 print(Studentslist:)

for st in students: # вывод полного списка студентов     print(st)   

 

#сортировка по фамилии, ключ сортировки определяется функцией SortParam: students = sorted(students,key=SortParam) 

 print(Sortedstudents:)

for st in students: #  вывод отсортированного списка     print(st) 

  print(badstudents:)

n=0 # счетчик количестванеуспевающих for st in students: #  вывод неуспевающих    for val in st.progress:

      if val<3 : # есть плохая оценка

        print(st) #выводим студента с плохой оцекой           n += 1          break if n == 0:

    print(no matches werefound.)


Поделиться статьей
Автор статьи
Анастасия
Анастасия
Задать вопрос
Эксперт
Представленная информация была полезной?
ДА
58.55%
НЕТ
41.45%
Проголосовало: 982

или напишите нам прямо сейчас:

Написать в WhatsApp Написать в Telegram

ОБРАЗЦЫ ВОПРОСОВ ДЛЯ ТУРНИРА ЧГК

Поделиться статьей

Поделиться статьей(Выдержка из Чемпионата Днепропетровской области по «Что? Где? Когда?» среди юношей (09.11.2008) Редакторы: Оксана Балазанова, Александр Чижов) [Указания ведущим:


Поделиться статьей

ЛИТЕЙНЫЕ ДЕФЕКТЫ

Поделиться статьей

Поделиться статьейЛитейные дефекты — понятие относительное. Строго говоря, де­фект отливки следует рассматривать лишь как отступление от заданных требований. Например, одни


Поделиться статьей

Введение. Псковская Судная грамота – крупнейший памятник феодального права эпохи феодальной раздробленности на Руси

Поделиться статьей

Поделиться статьей1. Псковская Судная грамота – крупнейший памятник феодального права эпохи феодальной раздробленности на Руси. Специфика периода феодальной раздробленности –


Поделиться статьей

Нравственные проблемы современной биологии

Поделиться статьей

Поделиться статьейЭтические проблемы современной науки являются чрезвычайно актуальными и значимыми. В связи с экспоненциальным ростом той силы, которая попадает в


Поделиться статьей

Семейство Первоцветные — Primulaceae

Поделиться статьей

Поделиться статьейВключает 30 родов, около 1000 видов. Распространение: горные и умеренные области Северного полушария . многие виды произрастают в горах


Поделиться статьей

Вопрос 1. Понятие цены, функции и виды. Порядок ценообразования

Поделиться статьей

Поделиться статьейЦенообразование является важнейшим рычагом экономического управления. Цена как экономическая категория отражает общественно необходимые затраты на производство и реализацию туристского


Поделиться статьей

или напишите нам прямо сейчас:

Написать в WhatsApp Написать в Telegram