Ооп в python реферат

Обновлено: 07.07.2024

В этой статье мы расскажем об объектно-ориентированном программировании (ООП) в Python и его фундаментальных концепциях.

Введение в ООП в Python

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

Одной из наиболее популярных парадигм является создание объектов. Она известна как объектно-ориентированное программирование (ООП).

Объект имеет две характеристики:

Рассмотрим на примере:

Объект – это попугай:

  • имя, возраст, цвет являются атрибутами;
  • пение, танцы — это поведение;

Концепция ООП в Python направлена ​​на создание кода для многократного использования. Эта концепция также известна как DRY (Don’t Repeat Yourself).

В Python концепция ООП реализует несколько принципов:

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

Класс

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

Примером для класса попугая может быть:

Мы используем ключевое слово class для определения пустого класса Parrot . Из класса мы создаем экземпляр – объект определенного класса.

Объект

Объект — это экземпляр класса. В определении класса задается только описание объекта. Пример создания объекта класса Parrot:

В данном случае obj является объектом класса Parrot.

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

Пример 1. Создание класса и объекта в Python

Результат работы программы:

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

Затем мы создаем экземпляры класса Parrot. В данном случае blu и woo являются ссылками на новые объекты.

После этого мы получаем доступ к атрибуту класса с помощью __class __.species. Атрибуты класса одинаковы для всех его экземпляров. Точно так же мы получаем доступ к атрибутам экземпляра, используя blu.name и blu.age. Но атрибуты экземпляра уникальны для каждого экземпляра класса.

Методы

Методы — это функции, определенные внутри класса. Они используются для определения поведения объекта.

Пример 2: Создание методов в Python

Результат работы программы:

В приведенном выше примере мы определяем два метода sing() и dance(). Их называют методами экземпляра, так как они вызываются для экземпляра объекта, то есть для blu.

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

Наследование — это способ создания нового класса на основе старого. Новый класс является производным классом (дочерним). Существующий класс является базовым классом (родительским).

Пример 3: Использование наследования в Python

Результат работы программы:

Сначала мы создали два класса: Bird (родительский класс) и Penguin (дочерний класс). Он наследует функции родительского класса. Это прослеживается в методе swim().

Дочерний класс изменил поведение родительского класса – метод whoisThis(). Также мы расширяем родительский класс, создав новый метод run().

Мы используем функцию super() перед методом __init__(), чтобы извлечь содержимое метода __init__() из родительского класса в дочерний.

Инкапсуляция

Пример 4: Инкапсуляция данных в Python

Когда мы запустим эту программу, результат будет следующим:

Сначала мы определили класс Computer . Затем использовали метод __init__() для хранения значения максимальной стоимости продажи компьютера.

Мы попытались изменить цену, но не смогли, потому что Python рассматривает __maxprice, как приватные атрибуты. Чтобы изменить значение, мы использовали функцию сеттера. То есть, setMaxPrice(), которая принимает цену в качестве параметра.

Полиморфизм

Полиморфизм — это способность использовать в ООП общий интерфейс для нескольких форм (типов данных).

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

Пример 5: Использование полиморфизма в Python

Мы определили два класса: Parrot и Penguin . У каждого из них есть общий метод fly(), но они разные.

Чтобы реализовать полиморфизм, мы создали общий интерфейс. То есть, функцию flying_test(), которая может принимать любой объект. Затем мы передали объекты blu и peggy в функцию flying_test().

Преимущества использования ООП

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

Пожалуйста, опубликуйте свои комментарии по текущей теме статьи. Мы очень благодарим вас за ваши комментарии, лайки, дизлайки, отклики, подписки!

Пожалуйста, опубликуйте ваши комментарии по текущей теме материала. За комментарии, дизлайки, подписки, отклики, лайки низкий вам поклон!

Пожалуйста, оставляйте ваши отзывы по текущей теме статьи. За комментарии, отклики, подписки, дизлайки, лайки низкий вам поклон!

Привет, Хабр! Представляю вашему вниманию перевод статьи “Object-Oriented Programming in Python vs Java” автора Джона Финчера.

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

Подробнее – под катом.

Примеры классов в Python и Java

Для начала давайте реализуем простейший класс в Python и Java, чтобы проиллюстрировать некоторые отличия в этих языках, и будем постепенно вносить в этот класс изменения.
Представим, что у нас есть следующее определение класса Car в Java:

Имя исходного Java-файла должно соответствовать имени хранящегося в нем класса, поэтому мы обязаны назвать файл Car.java. Каждый Java-файл может содержать только один публичный класс.
Такой же класс в Python будет выглядеть так:

В Python вы можете объявить класс где угодно и когда угодно. Сохраним этот файл как car.py.
Используя эти классы как основу, продолжим исследование основных компонентов классов и объектов.

Атрибуты объекта

Во всех объектно-ориентированных языках данные об объекте где-то хранятся. И в Python, и в Java эти данные хранятся в атрибутах, которые являются переменными, связанными с конкретными объектами.

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

Объявление и инициализация

В Java мы объявляем атрибуты (с указанием их типа) внутри класса, но за пределами всех методов. Перед тем, как использовать атрибуты класса, мы должны их определить:

В Python же мы объявляем и определяем атрибуты внутри метода класса init(), который является аналогом конструктора в Java:

Указывая перед именем переменных ключевое слово self, мы говорим Python-у, что это атрибуты. Каждый экземпляр класса получает свою копию. Все переменные в Python не типизированы (loosely typed), и атрибуты не являются исключением.

Переменные можно создать и за пределами метода init(), но это не будет лучшим решением и может привести к труднообнаруживаемым багам. Например, можно добавить объекту Car новый атрибут wheels следующим образом:

Однако, если мы забудем указать в 6-й строке выражение my_car.wheels = 5, то получим ошибку:

В Python если объявить переменную за пределами метода, то она будет рассматриваться как переменная класса. Давайте изменим класс Car:

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

Примечание: в Python обращение к переменной класса происходит по следующему синтаксису:

  1. Имя файла, содержащего класс (без расширения .py)
  2. Точка
  3. Имя класса
  4. Точка
  5. Имя переменной

Поскольку мы сохранили класс Car в файле car.py, мы обращаемся к переменной класса wheels в 6-й строчке таким образом: car.Car.wheels.

Работая с переменной wheels, необходимо быть обратить внимание на то, что изменение значения переменной экземпляра класса my_car.wheels не ведет к изменению переменной класса car.Car.wheels:

На 2-й и 3-й строчках мы определили два объекта Car: my_car и my_other_car.
Сначала свойство wheels у обоих объектов равно нулю. На 16-й строке мы установили переменную класса: car.Car.wheels = 4, у обоих объектов теперь по 4 колеса. Однако, затем когда на 24-й строке мы меняем свойство объекта my_car.wheels = 5, свойство второго объекта остается нетронутым.

Это означает, что теперь у нас две различные копии атрибута wheels:

  1. Переменная класса, которая применяется ко всем объектам Car
  2. Конкретная переменная экземпляра класса, которая применяется только к объекту my_car.
    Из-за этого можно случайно сослаться не на тот экземпляр и сделать малозаметную ошибку.

В Java эквивалентом атрибута класса является статичный (static) атрибут:

Обычно мы обращаемся к статичным переменным в Java через имя класса. Можно обратиться к ним и через экземпляр класса, как в Python, но это не будет лучшим решением.

Публичные и приватные

Java управляет доступом к методам и атрибутам, различая публичные и приватные данные.
В Java ожидается, что атрибуты будут объявлены как приватные (или защищенные — protected, если нужно обеспечить к ним доступ потомкам класса). Таким образом мы ограничиваем доступ к ним извне. Чтобы предоставить доступ к приватным атрибутам, мы объявляем публичные методы, которые устанавливают или получают эти данные (подробнее об этом – чуть позже).

Вспомним, что в нашем Java-коде переменная color была объявлена приватной. Следовательно, нижеприведенный код не скомпилируется:

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

Однако, в Java не приветствуется объявление атрибутов публичными. Рекомендуется объявлять их приватными, а затем использовать публичные методы, наподобие getColor() и getModel(), как и было указано в тексте кода выше.

В противоположность, в Python отсутствуют понятия публичных и приватных данных. В Python всё – публичное. Этот питоновский код сработает на ура:

Вместо приватных переменных в Python имеется понятие непубличных (non-public) переменных экземпляра класса. Все переменные, названия которых начинаются с одинарного подчеркивания, считаются непубличными. Это соглашение об именах нисколько не мешает нам обратиться к переменной напрямую.

Добавим следующую строку в наш питоновский класс Car:

Мы можем получить доступ к переменной _cupholders напрямую:

Python позволяет получить доступ к такой переменной, правда, некоторые среды разработки вроде VS Code выдадут предупреждение:


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

Теперь если мы обратимся к переменной __cupholders, мы получим ошибку:

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

Теперь возникает вопрос: если атрибут Java-класса объявлен приватным и атрибуту Python-класса предшествует в имени двойное подчеркивание, то как достучаться до этих данных?

Управление доступом

В Java мы получаем доступ к приватным атрибутам при помощи сеттеров (setters) и геттеров (getters). Для того чтобы пользователь перекрасил-таки свою машину, добавим следующий кусок кода в Java-класс:

Как было показано выше, в Python мы можем получить доступ к атрибутам напрямую. Поскольку всё – публичное, мы может достучаться к чему угодно, когда угодно и откуда угодно. Мы можем получать и устанавливать значения атрибутов напрямую, обращаясь по их имени. В Python мы можем даже удалять атрибуты, что немыслимо в Java:

Однако бывает и так, что мы хотим контролировать доступ к атрибутам. В таком случае нам на помощь приходят Python-свойства (properties).

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

Работу свойств можно увидеть на следующем примере класса Car:

В данном примере мы расширяем понятие класса Car, включая электромобили. В строке 6 объявляется атрибут _voltage, чтобы хранить в нем напряжение батареи.

В строках 9 и 10 для контролируемого доступа мы создаем функцию voltage() и возвращаем значение приватной переменной. Используя декоратор @property, мы превращаем его в геттер, к которому теперь любой пользователь получает доступ.

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

Обратите внимание, что мы используем voltage, а не _ voltage. Так мы указываем Python-у на то, что следует применять свойства, которые только что определили:

  • Когда в 4-й строке выводим значение my_car.voltage, Python вызывает функцию voltage(), декорированную @property.
  • Когда в 7-й строке присваиваем значение my_car.voltage, Python вызывает функцию voltage(), декорированную voltage.setter.
  • Когда в 13-й строке удаляем my_car.voltage, Python вызывает функцию voltage(), декорированную voltage.deleter.

Вышеприведенные декораторы дают нам возможность контролировать доступ к атрибутам без использования различных методов. Можно даже сделать атрибут свойством только для чтения (read-only), убрав декорированные функции @.setter и @.deleter.

self и this

В Java класс ссылается сам на себя, используя ключевое слово this:

this подразумевается в Java-коде. Его в принципе даже необязательно писать, кроме случаев, когда имена переменных совпадают.

Сеттер можно написать и так:

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

В Python ключевое слово self служит аналогичной цели: обращение к членам-атрибутам, но в отличие от Java, оно обязательно:

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

Отличие в том, как мы используем self и this в Python и Java, происходит из-за основных различий между двумя языками и от того, как они именуют переменные и атрибуты.

Методы и функции

Разница между рассматриваемыми языками заключается в том, что в Python есть функции, а в Java их нет.

В Python следующий код отработает без проблем (и используется повсеместно):

Мы можем вызвать say_hi() из любого места видимости. Эта функция не содержит ссылки на self, что означает, что это глобальная функция, а не функция класса. Она не сможет изменять или сохранять какие-нибудь данные какого-либо класса, но может использовать локальные и глобальные переменные.

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

Utils. SayHi() вызывается из любого места без предварительного создания экземпляра класса Utils. Поскольку мы вызываем SayHi() без создания объекта, ссылки this не существует. Однако, это всё равно не функция в том смысле, в котором является say_hi() в Python.

Наследование и полиморфизм

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

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

Обе эти фундаментальные ООП-концепции реализованы в Java и Python совершенно по-разному.

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

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

Чтобы продемонстрировать это, разделим класс Car на две категории: одну – для транспортных средств и одну – для машин, использующих электричество:

В классе Vehicle определены атрибуты color и model. В классе Device имеется атрибут _voltage. Класс Car происходит от этих двух классов, и атрибуты color, model и _voltage теперь являются частью нового класса.

В методе init() класса Car вызываются методы init() обоих родительских классов, чтобы все данные проинициализировались должным образом. После этого мы можем добавить классу Car любую желаемую функциональность. В данном примере мы добавим атрибут year, а также геттер и сеттер для _voltage.

Функциональность нового класса Car осталась прежней. Мы можем создавать и использовать объекты класса, как это делали несколькими примерами ранее:

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

Чтобы увидеть это, разделим Java-класс Car на родительский класс и интерфейс:

Не забываем, что каждый класс и каждый интерфейс в Java должны быть размещены в своем собственном файле.

Как и в вышеприведенном примере с Python, мы создаем новый класс Vehicle для хранения общих данных и функционала, присущих транспортным средствам. Однако для добавления функциональных возможностей Device нам нужно создать интерфейс, определяющий метод получения напряжения (voltage) устройства.

Класс Car создается путем наследования от класса Vehicle с использованием ключевого слова extends и реализации интерфейса Device с использованием ключевого слова implements. В конструкторе класса мы вызываем конструктор родителя при помощи super(). Поскольку родительский класс только один, мы обращаемся к конструктору класса Vehicle. Для реализации интерфейса переопределяем getVoltage() с помощью аннотации Override.

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

Так почему же это происходит с Java? Причина кроется в типах данных и проверке типов.

Типы данных и полиморфизм

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

Реализуем зарядку устройства для наших Java-объектов при помощи создания метода charge(), который принимает в качестве параметра переменную типа Device. Любой объект, реализующий интерфейс Device, может быть передан методу charge().

Создадим следующий класс в файле под названием Rhino.java:

Теперь создадим файл Main.java с методом charge() и посмотрим, чем отличаются объекты классов Car и Rhino.

Поскольку в классе Rhino не реализован интерфейс Device, его нельзя передать в качестве параметра в charge().

Лучше понять утиную типизацию поможет следующий аналогичный пример зарядки устройства на Python:

Дефолтные методы

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

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

toString() возвращает строковое представление объекта. По умолчанию это имя класса и адрес в памяти. Этот метод вызывается автоматически, когда объект передается в качестве параметра в метод, требующий строковый аргумент, например, System.out.println():

Запустим этот код и увидим дефолтное строковое представление объекта car:

Не очень информативно, не правда ли? Давайте усовершенствуем вывод, переопределив метод toString(). Добавим следующий метод в класс Car:

Теперь, запустив предыдущий пример, увидим следующее:

В Python подобный функционал обеспечивается набором так называемых магических методов (dunder — аббревиатура для double underscore). Каждый Python-класс наследует эти методы, и мы можем, переопределив их, изменить их поведение.

В Python для строкового представления объекта имеется два метода: repr() и str(). Однозначное представление объекта возвращается методом repr(), в то время как str() возвращает его в удобочитаемом виде. Это примерно как hashcode() и toString() в Java.

Как и в Java, в Python имеется дефолтная реализация магических методов:

Чтобы улучшить читаемость, переопределим метод str() в Python-классе Car:

Результат будет выглядеть намного приятнее:

Переопределение магического метода дало нам более читаемое представление объекта. Можно также переопределить метод repr(), это полезно для отладки.

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

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

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

Изменим наш Python-класс Car следующим образом:

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

О ОП — самая используемая парадигма программирования. Это одновременно и особый способ мышления, и отдельная методика. Её концепцию проще всего понимать на примерах из реальной жизни. И это неспроста. Объектно-ориентированное программирование помогает представлять содержимое программы наиболее естественным для нашего мира способом.

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

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

У класса есть свойства и функции (в ООП их называют методами).

  • Свойства — это характеристики, присущие данному конкретному множеству объектов.
  • Методы — те действия, которые они могут совершать.

Свойствами класса "автотранспорт" могут быть, например: год выпуска, вид и цвет. На уровне объектов это будет выглядеть так: Бьюик Электра — это объект класса "Автотранспорт" со следующими свойствами:

  • вид — легковой автомобиль;
  • цвет — чёрный;
  • год выпуска — 1968.

Можно сказать, что объект — это вполне конкретный экземпляр класса

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

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

В Питоне класс "Автотранспорт" может выглядеть так:

Теперь никто не помешает нам получить собственную красную феррари. Пусть и в симуляторе.

Принципы ООП

Абстракция

Абстракция — это выделение основных, наиболее значимых характеристик объекта и игнорирование второстепенных.

Любой составной объект реального мира — это абстракция. Говоря "ноутбук", вам не требуется дальнейших пояснений, вроде того, что это организованный набор пластика, металла, жидкокристаллического дисплея и микросхем. Абстракция позволяет игнорировать нерелевантные детали, поэтому для нашего сознания это один из главных способов справляться со сложностью реального мира. Если б, подходя к холодильнику, вы должны были иметь дело с отдельно металлом корпуса, пластиковыми фрагментами, лакокрасочным слоем и мотором, вы вряд ли смогли бы достать из морозилки замороженную клубнику.

Полиморфизм

Полиморфизм подразумевает возможность нескольких реализаций одной идеи. Простой пример: у вас есть класс "Персонаж", а у него есть метод "Атаковать". Для воина это будет означать удар мечом, для рейнджера — выстрел из лука, а для волшебника — чтение заклинания "Огненный Шар". В сущности, все эти три действия — атака, но в программном коде они будут реализованы совершенно по-разному.

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

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

Мы могли бы сделать отдельный класс "Грузовик", который является наследником "Автотранспорта". Объекты этого класса могли бы определять все прошлые атрибуты (цвет, год выпуска), но и получить новые. Для грузовиков это могли быть грузоподъёмность, снаряженная масса и наличие жилого отсека в кабине. А методом, который есть только у грузовиков, могла быть функция сцепления и отцепления прицепа.

Инкапсуляция

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

Вы разработали для муниципальных служб класс "Квартира". У неё есть свойства вроде адреса, метража и высоты потолков. И методы, такие как получение информации о каждом из этих свойств и, главное, метод, реализующий постановку на учёт в Росреестре. Это готовая концепция, и вам не нужно чтобы кто-то мог добавлять методы "открыть дверь" и "получить место хранения денег". Это А) Небезопасно и Б) Избыточно, а также, в рамках выбранной реализации, не нужно. Работникам Росреестра не требуется заходить к вам домой, чтобы узнать высоту потолков — они пользуются только теми документами, которые вы сами им предоставили.

Класс

Классы, в некотором смысле, подобны чертежам: это не объекты сами по себе, а их схемы. Класс "банковских счетов" имеет строго определенные и одинаковые для всех атрибуты, но объекты в нём — сами счета — уникальны.

Как в Python создать класс

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

class SimpleClass: pass

Для именования классов в Python обычно используют стиль "camel case", где первая буква — заглавная.

Конструктор

Метод, который вызывается при создании объектов, в ООП зовётся конструктором. Он нужен для объектов, которые изначально должны иметь какие-то значение. Например, пустые экземпляры класса "Студент" бессмысленны, и желательно иметь хотя бы минимальный обозначенный набор вроде имени, фамилии и группы.

В качестве Питоновского конструктора выступает метод __init__() :

class Student: def __init__(self, name, surname, group): self.name = name self.surname = surname self.group = group alex = Student("Alex", "Ivanov", "admin")

Атрибуты класса

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

Поля могут быть статическими и динамическими:

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

☝️ Обратите внимание — статический и динамический атрибут может иметь одно и то же имя:

Методы класса

Метод — это функция класса.

Например, у всех научно-фантастических космических кораблей есть бортовое оружие. И оно может стрелять.

class SpaceShip: def atack(self): print('Пиу!') star_destroyer = SpaceShip() star_destroyer.atack() > Пиу!

Что такое self?

Аналог этого ключевого слова в других языках — слово this . self — это всего лишь ссылка на текущий экземпляр класса.

🐈 Отличный пример с котофеями:

  1. Все котики умеют мурлыкать;
  2. Эта способность реализована в классе Кот , как метод Мурчать ;
  3. Вы хотите, чтобы ваш кот по имени Пушок помурчал;
  4. Если сделать так: Кот.Мурчать , то мурлыкать начнут все коты во Вселенной;
  5. Но так как вам нужен один конкретный кот, то нужно вызвать метод иначе: self.Мурчать ;
  6. Сделано. Пушок мурлыкает.

Уровни доступа атрибутов и методов

В Питоне не существует квалификаторов доступа к полям класса. Отсутствие аналогов связки public/private/protected можно рассматривать как упущение со стороны принципа инкапсуляции.

Декораторы

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

Объекты или экземпляры класса

Чем объекты отличаются от классов

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

Как создать объект класса в Python

Если у нас есть реализация класса, то его экземпляр создать очень просто:

Атрибуты объекта

Атрибуты класса могут быть динамическими и статическими. На уровне объекта они инициализируются так:

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

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

Мы все прекрасно знаем, что котики, к примеру, любят всё ронять, а собакены — рыть землю. Создадим два соответствующих класса-наследника:

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

Tom = Cat() Tom.make_a_sound() > Издаёт животный звук Tom.drop_everything() > Вставай скорее, я всё уронил!

Переопределение

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

Документирование классов

Весь код нужно комментировать и документировать. Классы — не исключение. Стоит помнить, что код вы пишите не для себя, и вполне вероятно, что написанное вами придётся поддерживать другим людям. Комментарии повышают читаемость и увеличивают легкость восприятие кода в разы, тем самым экономя время и деньги.

Документирование кода в Python

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

Языки программирования постоянно появляются, как и разные методологии. Объектно-ориентированное программирование является одной из таких методологий, которая стала довольно популярной за последние несколько лет.

В этой главе рассказывается об особенностях языка программирования Python, который делает его объектно-ориентированным языком программирования.

Схема классификации языкового программирования

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

Что такое объектно-ориентированное программирование?

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

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

Объектно-ориентированный анализ (OOA) — это процесс изучения проблемы, системы или задачи и определения объектов и взаимодействий между ними.

Почему стоит выбрать объектно-ориентированное программирование?

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

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

Облегчает простое обслуживание и модификацию существующего кода.

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

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

Придает код многократного использования

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

Облегчает простое обслуживание и модификацию существующего кода.

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

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

Придает код многократного использования

Процедурное и объектно-ориентированное программирование

Процедурное программирование происходит от структурного программирования, основанного на понятиях функций / процедур / процедур . Легко получить доступ и изменить данные в процедурно-ориентированном программировании. С другой стороны, объектно-ориентированное программирование (ООП) позволяет разложить проблему на несколько единиц, называемых объектами, а затем построить данные и функции вокруг этих объектов. В нем больше внимания уделяется данным, чем процедуре или функциям. Также в ООП данные скрыты и недоступны для внешних процедур.

В таблице на следующем рисунке показаны основные различия между подходами POP и OOP.

Разница между процедурно-ориентированным программированием (POP) и Объектно-ориентированное программирование (ООП).

Принципы объектно-ориентированного программирования

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

ой

Давайте кратко разберем каждый из столпов объектно-ориентированного программирования —

Инкапсуляция

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

наследование

абстракция

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

Читайте также: