Python — объектно-ориентированный язык программирования. В отличие от процедурно-ориентированного программирования, ООП опирается на объекты.
Объект — это набор данных (переменных) и методов (функций), которые с этими данными взаимодействуют.
Представьте чертеж дома. В нем содержится вся информация: сколько этажей, какого размера двери, окна и т. д. На основе это чертежа мы можем построить дом. Дом — это объект.
По одному чертежу можно построить сразу несколько домов. Так же и с классом — по нему можно создать много объектов. Объект также можно назвать экземпляром класса, а процесс его создания — инстанцированием.
Как объявить класс
По аналогии с функциями, которые начинаются с def , объявление класса сопровождается ключевым словом class .
Первая строка внутри класса называется строкой документации, в ней содержится краткое описание класса. Писать ее рекомендуется, но не обязательно.
class MyNewClass: »’Это строка документации. Мы создали новый класс»’ pass
Класс создает новое локальное пространство имен, где определяются все атрибуты. Атрибутами могут быть и переменные, и функции.
Java класс, объект, ссылка на объект — в чем разница? (перезалив)
Есть и специальные атрибуты, которые начинаются с двойного нижнего подчеркивания __ . Например, __doc__ — строка документации класса.
После объявления класса создается объект этого класса с тем же именем. Этот объект класса позволяет нам как получить доступ к различным его атрибутам, так и инстанцировать новые объекты этого класса.
class Person: «Это класс, описывающий человека» age = 10 def greet(self): print(‘Привет’) # Вывод: 10 print(Person.age) # Вывод: print(Person.greet) # Вывод: ‘Это мой второй класс’ print(Person.__doc__)
Вывод:
10
Это класс, описывающий человека
Как создать объект
Что такое объект
Недавно работал над задачей. Нужно было получить из сети некоторые объекты по REST и обработать.
Ну все вроде бы ничего сложного. Загрузил, спарсил, вернул. Ок. Затем нужно было полученный массив обработать. Вкратце, по особой логике просуммировать некоторые поля — это могла быть строка, число или null.
Начал делать как обычно: создал переменную sum, начал цикл for, в нем начал заниматься основной логикой. Закончил.
Продолжил кодить. Хоба! Эта же логика. Не стал копипастить, вынес в отдельную функцию. Тоже все хорошо.
Начал заниматься 3 задачей. Объединить результаты нескольких вычислений. Опять циклом начал перебирать. Но тут появилась мысль:
“А что, если создать для этого отдельный объект?”
Да нет, чушь! Ведь не существует в реальном мире ОбъединителяКакогоТоРезультата. Но что, если сделать? Попробуем.
Какого. Почему все вмиг стало так просто? Передал в конструктор нужные объекты и сделал методы, которые применяли свою логику к содержащимся в них объектам. Всего-лишь несколько строчек! Почему я так раньше не делал?
Я раззадорился. Начал видеть объекты везде. Это очень удобно: не нужно смотреть на каждый фрагмент кода с мыслью “а было ли это где нибудь раньше?”. А как тестировать легче стало!
Что такое объекты в программировании?
Тут до меня дошло, что было со мной не так:
Я не разграничивал объекты реального мира и объекты в понимании ООП.
Объекты ООП != Объекты реального мира
Наверное главной моей ошибкой был недостаток практики: я много интересовался, читал, смотрел, но до кодирования руки не доходили. Поэтому, к моменту того события в моей голове было только 3 паттерна использования объектов:
- DTO
- Объекты из реального мира
- Объекты, реализующие какой-то интерфейс (обычно для запросов по сети, для использования в DI контейнера)
Оглядевшись назад понял, что все дороги вели именно к такому мышлению:
- В вузе нас учили ООП по каким-то моделям типа: “Вот это объект Человек. У него есть атрибуты Имя и Возраст”, а когда дело доходило до программирования, никто не смотрел как мы пишем код. Получалась каша из императивного программирования и набросков объектов.
- Во всяких обучающих ресурсах (видео, книги, курсы) дают слишком простые примеры. Примеры слишком прямолинейные (как в выше перечисленном вузе). Не дают почувствовать мощь объектов.
- Если были задачи, то слишком простые. Не тот уровень сложности, чтобы действительно над чем-то задуматься (например, приевшийся калькулятор). Они не показывали, что объекты могли бы решить многие проблемы.
В программе полно таких неявных объектов — служебных объектов: считают, фильтруют, агрегируют. Никогда не задумывался над тем, что практически любой for можно (наверное, даже лучше) заменить на объект, инкапсулирующий необходимую логику.
Пожалуй единственное, что меня ограничивало — идефикс, того, что объекты должны представлять концепции реального мира. Кто мне вообще это сказал?
Диаграммы мешают в понимании ООП
Но что насчет популярных инструментов проектирования? Нотаций. Наверное все видели различные UML диаграммы. Диаграмму классов так наверное любой программист должен был видеть хоть раз.
ER диаграммы тоже хороши — они слишком сильно сцеплены с реальным миром. Там почти все представляет объекты реального мира.
Поразмыслив, я понял 3 вещи:
- ER диаграмма ничего не имеет общего с ООП — это инструмент для бизнес-анализа. Я не обязан создавать такие же классы, как и на этой диаграмме. Кто мне такое сказал?
- UML показывает высокоуровневую структуру программы: кто в ней есть и что они должны делать/иметь. Т.е. что делать, а не как делать. Реализация ложится на плечи программиста (спойлер, это будут методы на 100+ строк из циклов, условий и других прелестей)
- Многие нотации ориентированы для простого понимания концепций программы — из каких компонентов состоит. Ничто не мешает нам вместо классов передавать массивы object. Не нужно ориентироваться на них как на истину в первой инстанции.
В итоге заканчиваем, тем что имеем много объектов. Ура, ООП! А что внутри? Громадные циклы на десятки строк, множество флагов и if’ов — полная императивщина.
Да о чем я говорю?
Что же я понял? Например,
public interface IWorkingScheduleService < // Возвращает тип дня: рабочий, предпраздничный, праздничный, выходной int GetDayType(DateOnly date); >
// Количество рабочих часов на каждый день недели public class UserSchedule < public float Monday < get; set; >public float Tuesday < get; set; >public float Wednesday < get; set; >public float Thursday < get; set; >public float Friday < get; set; >public float Saturday < get; set; >public float Sunday < get; set; >>
Задача — посчитать общее время рабочих часов.
Банально, да? Давайте сделаем функции:
public static class ScheduleHelpers < public static float GetTotalWorkingHours(IWorkingScheduleService service, UserSchedule schedule, DateOnly from, DateOnly to) < // Какая-то логика return 0; >public static float GetTotalWorkingHoursWithoutPreholiday(IWorkingScheduleService service, UserSchedule schedule, DateOnly from, DateOnly to) < // Какая-то логика return 0; >public static float GetTotalHolidayWorkingHours(IWorkingScheduleService service, UserSchedule schedule, DateOnly from, DateOnly to) < // Какая-то логика return 0; >>
Но тут мы заметим общую начальную часть: IWorkingScheduleService service, UserSchedule schedule . Почему бы нам не вынести эту логику в отдельный объект?
public class WorkingScheduleCalculator < private readonly IWorkingScheduleService _service; private readonly UserSchedule _schedule; public WorkingScheduleCalculator(IWorkingScheduleService service, UserSchedule schedule) < _service = service; _schedule = schedule; >public float GetTotalWorkingHours(DateOnly from, DateOnly to) < // Какая-то логика return 0; >public float GetTotalWorkingHoursWithoutPreholiday(DateOnly from, DateOnly to) < // Какая-то логика return 0; >public float GetTotalHolidayWorkingHours(DateOnly from, DateOnly to) < // Какая-то логика return 0; >>
Как же стало удобно! Все находится рядом, сигнатуры стали короче и поддержка автодополнения в подарок — прелесть!
Выводы
Что я вынес из всего этого?
- Объект это не концепция реального мира. Можно сделать объект который имеет имя, атрибуты, поведение, как у объекта реального мира, сделать максимально похожим, но это НЕ ОБЪЕКТ РЕАЛЬНОГО МИРА. Надо прекратить думать в данном ключе! Объект — это (всего лишь) данные и функции, ассоциированные с ними
- На каждый блок с логикой (цикл, последовательность условий и т.д.) я смотрю с мыслью: “Нельзя ли вынести это в отдельный объект?”
- Таким же образом, смотрю на функции, которые принимают одинаковые аргументы. Их всех можно объединить в объекты, атрибутами которых являются эти общие аргументы.
P.S. Я не радикал, а за осмысленное и прагматичное использование объектов: для тривиальной логики можно оставить циклы, разрешаю)
Источник: habr.com
Лекции / ОБЪЕКТЫ И КЛАССЫ
программирования С++ от С состоит в том, что в языке программирования С нет классов, а, следовательно, язык С не поддерживает ООП, в отличие от С++. §9.1 Определение объекта Объект – это достаточно общее и широкое понятие, которое может иметь разные трактовки. В широком смысле слова объект – это любая сущность, имеющая некоторый набор свойств (параметров, характеристик) и обладающая некоторым поведением (функциональностью).
Отсюда следует, что объектом может быть практически все, что угодно – материальные предметы (компьютер, автомобиль, человек), логические понятия (файл, документ, таблица, список, управляющая кнопка, окно в многооконной графической системе, форма, приложение), математические понятия (например, геометрические объекты типа отрезок или окружность). Например, когда вы смотрите на человека, вы видите его как объект.
При этом объект определяется двумя компонентами: свойствами и поведением. У человека имеются такие свойства как цвет глаз, возраст, вес и т.д. Человек также обладает поведением, то есть он ходит, говорит, дышит и т.д.
Свойства и поведение объекта содержатся в объекте одновременно . Слово «одновременно» в данном случае определяет ключевую разницу между ООП и другими методологиями программирования. При ООП атрибуты и поведения размещаются в рамках одного объекта, в то время как при процедурном или структурном программировании атрибуты и поведение обычно разделяются. Под объектом в узком смысле можно понимать некоторое формализованное описание рассматриваемой сущности, т.е. модель исходного объекта . Для такого описания нужен некоторый язык, например – язык программирования. В этом случае объект становится элементом языка, и именно в таком контексте он и будет рассматриваться далее. Моделирование реальных объектов – это важнейший этап разработки объектных программ, во многом определяющий успех всего проекта. Необходимо понимать, что любая модель – это только часть исходного 2
моделируемого объекта, отражающая те свойства и атрибуты объекта, которые наиболее важны с точки зрения решаемой задачи. Изменение постановки задачи может привести к существенному изменению модели. Особенно это характерно для сложных объектов.
Вряд ли имеет смысл строить всеобъемлющую модель «на все случаи жизни», поскольку такая модель будет очень громоздкой и практически непригодной для использования. Поэтому один из важнейших принципов построения моделей – это принцип абстрагирования , т.е. выделение наиболее существенных для решаемой задачи черт исходного объекта и отбрасывание второстепенных деталей. Отсюда следует, что для одного и того же исходного объекта можно построить разные модели, каждая из которых будет отражать только наиболее важные в данный момент черты объекта. Исходный объект
Описание 1 | Описание 2 | Описание 3 |
Например, для | исходного объекта | «человек» можно построить |
следующие информационные модели: человек как студент учебного заведения человек как сотрудник организации человек как пациент учреждений здравоохранения человек как клиент государственных органов управления и т.д. Из этого примера видно, что весьма часто различные модели одной и той же исходной сущности «пересекаются», имеют общие свойства (это отражено и на приведенной выше схеме): все студенты, сотрудники, клиенты имеют фамилию, дату рождения, место проживания, пол и т.д. 3
Как показала практика последних 10-15 лет, использование объектов при разработке сложных информационных систем оказалось очень удачным решением. Заказчики информационных систем, как правило, не являются специалистами в области программного обеспечения и поэтому не воспринимают такие программистские термины как переменные, подпрограммы, массивы, файлы и т.д.
Гораздо легче воспринимаются объекты как элементы предметной области. Разработчики на основе общения с заказчиком и на основе анализа предметной области должны построить адекватные описания основных сущностей решаемой задачи, перевести эти описания в необходимый формальный вид и создать объектную программу как набор взаимодействующих объектов . Достоинством объектных программ является их четкая структуризация – каждый объект выполняет свою строго определенную задачу, а их совместная работа позволяет достичь поставленных целей. Программный объект – это условное понятие, с которым связывается набор некоторых данных и программный код обработки этих данных объект : данные + программный код Основное преимущество ООП заключается в том, что и данные, и операции (код), используемые для манипулирования ими, инкапсулируются в одном объекте. Например, при перемещении объекта по сети он передается целиком, включая данные и поведение. Объединение в рамках объекта некоторых данных и соответствующего программного кода рассматривается как проявление одного из базовых принципов объектного подхода – принципа инкапсуляции ( encapsulation ). Инкапсуляция позволяет рассматривать объект в виде некоторой достаточно самостоятельной программной единицы , полностью отвечающей за хранение и обработку своих данных и предоставляющей посторонним пользователям четко определенный набор услуг. Однако объект — это не 4
только поставщик услуг, но чаще всего еще и потребитель услуг других объектов. Хорошим примером этой концепции является объект, загружаемый браузером. Часто бывает так, что браузер заранее не знает, какие действия будет выполнять определенный объект, поскольку он еще «не видел» кода. Когда объект загрузится, браузер выполнит код, содержащийся в этом объекте, а также использует заключенные в нем данные. Относительно связываемых с объектом данных надо отметить следующее: 1. каждый элемент данных часто называют свойством объекта (хотя есть и различия в трактовке этого термина) 2. объект может содержать любое разумное число данных-свойств 3. набор данных-свойств определяется при описании объекта и при выполнении программы изменяться не может, могут изменяться лишь значения свойств 4. текущие значения свойств определяют текущее состояние объекта 5. для хранения значений свойств необходима память (как для обычных переменных), и поэтому объекты программы потребляют оперативную память 6. свойства могут иметь разные типы: простейшие (целочисленные, символьные, логические), структурные (строки, массивы, списки) и даже объектные 7. в соответствии с принципом инкапсуляции элементы данных рекомендуется делать недоступными для прямого использования за пределами объекта ( закрытость данных) В качестве примеров свойств можно привести: объект «Студент»: фамилия, имя, дата рождения, место проживания, группа, специальность, массив оценок; объект «Файл»: имя, размер, дата создания, тип; 5
объект «Окно»: положение на экране, размеры, тип, фон заполнения, тип рамки, оформление заголовка; объект «Автомобиль»: стоимость, тип, марка, мощность двигателя, цвет и т.д.; объект «Окружность»: координаты центра, радиус, цвет. Относительно связываемого с объектом программного кода необходимо отметить следующие моменты: программный код разбивается на отдельные подпрограммы , которые принято называть методами набор методов определяет выполняемые объектом функции и тем самым реализует поведение объекта набор методов определяется при описании объекта и при выполнении программы уже не изменяется методы могут иметь ограничения по доступности : некоторые методы можно сделать недоступными ( закрытыми ) за пределами объекта, но всегда должен быть определен набор открытых методов, образующих внешний интерфейс объекта вызов одного из открытых методов соответствует запросу услуги, реализуемой данным методом среди методов выделяют один или несколько специальных методов- конструкторов и иногда – один метод-деструктор , назначение которых рассматривается чуть дальше в соответствии с принципом инкапсуляции для доступа извне к закрытым данным могут вводиться специальные методы доступа Еще одна группа очень часто используемых методов – это методы доступа к закрытым свойствам объекта. Введение таких методов позволяет организовать контролируемый доступ к внутренним данным объекта. В общем случае для закрытого свойства можно ввести два метода доступа: 6
метод для чтения хранящегося в свойстве значения (часто такие методы называют get-методами ) метод для изменения значения свойства ( set-метод ) Набор используемых с каждым свойством методов доступа определяется при разработке объекта и позволяет для каждого свойства организовать необходимый уровень доступа . Если объявлены оба метода, то пользователи имеют полный доступ к соответствующему свойству. Если объявлен только get-метод , то пользователь может лишь просматривать значение свойства, но не изменять его.
Наконец, если для свойства нет ни одного метода, то такое свойство полностью закрыто для пользователя. Иногда set-методы кроме изменения значений свойств выполняют некоторую дополнительную работу, например – проверяют новые значения свойств. Кроме конструкторов и методов доступа, объекты практически всегда имеют еще и некоторый набор специфических методов, определяющих функциональность объекта. Например: объект «Окружность»: отображение на экране, перемещение, растяжение/сжатие, вычисление длины окружности. объект «Список»: добавление элемента, удаление элемента, поиск элемента, сортировка элементов; объект «Окно»: отображение, перемещение, изменение атрибутов, изменение размеров; объект «Студент»: посещение занятий, выполнение заданий, сдача контрольных точек, оплата обучения; В итоге объектная программа представляет собой набор взаимодействующих объектов, которые обращаются друг к другу за выполнением необходимых действий. 7
Рисунок 9.1 При этом каждый объект проходит определенный жизненный цикл: 1. объект создается методом-конструктором 2. объект используется другими объектами, предоставляя им свои открытые методы и неявно – закрытые данные 3. объект уничтожается (явно деструктором или неявно механизмом сборки мусора) Очевидно, что при работе объектной программы одновременно может существовать множество однотипных программных объектов (множество файлов, множество окон, множество студентов). Поэтому необходим инструмент формального описания таких однотипных объектов и в качестве такого инструмента выступает следующее важнейшее понятие объектного подхода — класс. §9.2 Определение классов Класс представляет собой формализованный способ описания однотипных объектов , т.е. объектов с одинаковым набором свойств и методов . Именно при описании класса перечисляются свойства и реализуются методы соответствующих объектов. Разработка объектной программы начинается с описания необходимых классов. На основе одного класса можно создать любое разумное (все ресурсы вычислительной системы конечны!) число объектов, называемых 8
экземплярами этого класса. Все используемые в программе объекты должны быть экземплярами некоторых классов, стандартных или собственных. Соответствие между понятиями «объект» и «класс» аналогично соответствию между понятиями «переменная» и «тип данных». Правила описания классов различны для разных языков, тем не менее можно отметить ряд общих моментов.
Описание класса включает в себя: заголовок класса, включающий специальную директиву class и имя класса; практически всегда в заголовке класса задается дополнительная информация о классе; тело класса, содержащее перечень свойств (полей данных), заголовки методов и их программную реализацию (не всегда). В классах допускается объявлять так называемые абстрактные методы, у которых есть только заголовок (имя и параметры), но нет программной реализации . Если класс содержит хотя бы один абстрактный метод, он сам считается абстрактным . Важная особенность абстрактных классов состоит в том, что объекты-экземпляры на их основе создавать нельзя ! Абстрактные классы используются для описания абстрактных понятий. Общие правила описания свойств: • каждое свойство объявляется как обычная переменная, т.е. для нее обязательно задается имя и тип (простейший, структурный или объектный) • имена всех свойств в классе должны быть различными • свойства рекомендуется объявлять закрытыми с помощью специальной директивы private (такие свойства доступны для прямого использования только внутри методов данного класса); открытые свойства (если необходимо нарушить принцип инкапсуляции) объявляются с помощью директивы public . Общие правила описания методов: 9
• метод оформляется как обычная подпрограмма, с указанием имени , формальных параметров (если необходимо) и типа возвращаемого значения • допускается объявлять несколько методов с одним и тем же именем, но разными наборами формальных параметров (так называемая перегрузка методов, overloading ); наборы параметров должны отличаться либо их числом, либо типами параметров • каждый метод должен быть объявлен либо как открытый (директива public ), либо как закрытый ( private ); закрытые методы могут использоваться только другими методами данного класса • метод может быть объявлен статическим ; такой метод можно вызывать БЕЗ создания объектов! • абстрактные методы объявляются с помощью директивы abstract • методы доступа для чтения значений закрытых свойств (Get- методы) рекомендуется именовать с префиксом Get (например, GetColor, GetSize) и оформлять как функцию без параметров, возвращающую тип соответствующего свойства • методы доступа для изменения значений закрытых свойств (Set- методы) рекомендуется именовать с префиксом Set (например, SetColor, SetSize) и оформлять как процедуру (void-функцию) с одним входным параметром В ООП существует три основных принципа построения классов: 1. Инкапсуляция — это свойство, позволяющее объединить в классе и данные, и методы, работающие с ними и скрыть детали реализации от пользователя. 2. Наследование — это свойство, позволяющее создать новый класс-потомок на основе уже существующего, при этом все характеристики класса родителя присваиваются классу-потомку. 10
Источник: studfile.net