Почему в Python плохой ООП / Хабр

В Python ужасный ООП. Кликбейтный тезис, который имеет право на существование. Есть много языков, где ООП представлен не в самом классическом виде, ну или так принято считать. Прототипные JavaScript и Lua, Golang с прикреплением методов и прочие. Но «не такой как все» всегда ли синоним слова «неправильный»?  С чего мы вообще вязли, что ООП в Python не такой каким должен быть ООП? Что вообще является точкой отсчёта «правильности» ООП? Smalltalk или Simula 67? Вроде бы объектно-ориентированное программирование – это просто парадигма.. или уже догма?

В этом статье мы попробуем понять:

  • что не так с ООП в Python;

  • чем его ООП отличается от языков с эталонной по мнению многих реализацией ООП: Java, C# и С++;

  • почему разработчики языка Python решили сделать всё именно так.

Реализует этот текст автор YouTube-канала PyLounge Макс. Поехали!

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

Для начала необходимо понять. Чем ООП в Python отличается от классической концепции и реализации в других ЯП.

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

Ключевыми особенностями ООП является понятия:

  • абстракция; 

  • инкапсуляция; 

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

  • полиморфизм.

Алан Кэй, создателя языка Smalltalk, одним из «отцов-основателей» ООП, говорил, что ООП подход заключается в следующем наборе принципов:

  1. Всё является объектом.

  2. Вычисления осуществляются путём взаимодействия (обмена данными) между объектами, при котором один объект требует, чтобы другой объект выполнил некоторое действие.

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

  4. Каждый объект является представителем класса, который выражает общие свойства объектов (таких, как целые числа или списки).

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

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

«ООП для меня означает лишь обмен сообщениями, локальное сохранение, и защита, и скрытие состояния, и крайне позднее связывание». (c) Алан Кэй

Другими словами, в соответствии с идеями Алана Кэя, самыми важными ингредиентами ООП является:

  1. Передача сообщений (то есть взаимодействие).

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

  3. Динамическое связывание.

Интересно, что указывается именно термин связывание, а терминов наследование и полиморфизм нет. Ведь полиморфизм бывает статический (раннее связывание) – это перегрузки и дженерики (шаблоны).  То есть Кэй, человек, который считается изобретателем термина «ООП» не считал важными частями ООП наследование и полиморфизм. Получается пропорции условны, а границы размыты.

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

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

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

Например, в Java можно определить поле как приватное, и тогда оно будет видно только членам этого класса. Также работает и С++, однако там есть концепция друзей (friend), которые могут видеть приватные поля других классов, что сильно критикуется.

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

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

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

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

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

ООП пытается сделать программное обеспечение похожим на «реальный мир», как его может понять обычный человек.

Современная идея ООП — это синтез всех их идей, а также идей Голдберга, Барбары Лисков, Дэвида Парнаса, Бертрана Мейера, Гюля Ага и других. Но никто из них не может утверждать, что же такое «ООП». Термины развиваются, как и задачи, которые изначально эти инструменты должны были решать.

А что же касаемо Python. Python полностью удовлетворяет всем перечисленным выше требования, а значит является «полностью объектно-ориентированным». ООП – просто стиль.

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

Отсутствие модификаторов доступа

В Python отсутствует деление на публичные, защищённые, приватные свойства и методы.   Многие вещи в Python основаны на соглашениях. Сокрытие данных реализуется чисто конвенционально. За счёт соглашения использовать подчёркивание у свойств и методов (защищённые члены). Да, можно использовать двойное подчёркивание, так называемый манглинг. Чисто технически это запрещает прямой доступ к данным и равносильно модификатору приват, но это скорее придуманный адептами классического ООП «грязный хак». Таким образом, в Python нет классического разделения на группы доступа, потому что Python доверяет разработчику. В этом плане Python ближе к С++.

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

Мне кажется, инкапсуляция не так полезна в языке с динамической типизацией.  Выскажу непопулярное мнение – это не добавляет никакой безопасности, она просто дает ощущение безопасности. Если вы грамотный программист, то так или иначе сделаете всё как надо.

Но почему разработчики языка не добавили такой привычный «предохранитель»? Ответ кроется в философии Python. Гвидо не любит что-то скрывать. Как он выразился в одном интервью: «мы все здесь взрослые по обоюдному согласию. Python доверяет вам. Он говорит: «Эй, если хочешь чтобы ковыряться в темных местах, я надеюсь, что у тебя есть уважительная причина, и вы не создаете проблем». Этого тезиса мы ещё коснёмся ниже. Пока просто запомните.

Вообще инкапсуляция – это не совсем про сокрытие. Инкапсуляция определяется как «процесс объединения элементов данных и функций в единое целое, называемое классом» или «отделение реализации от описания». Таким образом, номинально в Python всё соблюдается более чем верно.

Отсутствие интерфейсов

В языке Python нет как таковой конструкции как интерфейс (interface). К слову в С++ их тоже нет. Но что в Python, что в С++, есть механизмы, позволяющие так или иначе использовать интерфейсы.  Абстрактные классы ­– это хоть и немного другое, но функционалу отвечает и допускает некоторое упрощение концепции. На мой взгляд, отсутствие интерфейсов искусственный механизм избежания неоднозначности. Вот у тебя есть абстрактные классы, вот их и используй. С помощью абстрактных классов можно сделать всё тоже что и с интерфейсами, но не надо заморачиваться. Ведь Python идёт по пути простоты и убирает всё лишнее. Создатели языка даже конструкцию switch case выкинули, дабы «место не занимала».

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

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

Утиная типизация

Она, конечно, к теме относится косвенно. Но, тем не менее, рядом с Python всегда всплывает понятие утиной типизации.  

Если что-то выглядит как утка, плавает как утка и крякает как утка, это наверняка и есть утка.

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

Тут во всей красе демонстрируется один из главных принципов Дзена Python«явное лучше, чем неявное». Если что-то выглядит как утка и крякает, то это утка, к чему погружаться в экзистенциальные копания и вопросы самоопределения? Будь проще и посмотри пример.

Поскольку Duck и Human это разные классы, Python повторно вызывает функцию fly_quack() для экземпляра класса Human. И хотя класс Human имеет похожие методы quack и fly , типы объектов были разными и поэтому все работает правильно и вызываются верные методы.

Константные методы

Нет способов предотвратить изменение состояния класса методами класса (константные методы), снова всё полагается на добрую волю программиста.

Вообще докопаться ещё можно много до чего. Например, не совсем стандартное описание статических методов и свойств, параметр self, MRO и многое многое другое.

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

The Zen of Python

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

По мнению многих Smalltalk — самый чистый ООП язык, но что даёт и какова цена этой чистоты? Можно написать очень хороший объектно-ориентированный код как на Smalltalk, так и на Python.

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

Есть языки, которые идут по одному из двух векторов развития: доверяют разработчику, дают средства и возможности, за что он может заплатить неправильностью своих решений. И языки, которые по максимуму всё запрещают, чтобы писать было просто и топорно. Все решения давно приняты за тебя, всем известно как делать правильно, например, Golang. С такой точки зрения «Почти все «фичи» — это сахарная кола, а программирование — это толстяк с диабетом»».

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

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

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

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

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

Проблема в том, что люди пытаются перенять подходы из других языков, а не учатся использовать уникальные сильные стороны Python. У Python довольно надежная объектная модель, но это объектная модель Python, а не C++, Java или…кого-то другого.

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

А Python просто сейчас очень популярен. Он своего рода фронтмен, а тот кто на передовой, того обычно и критикуют. И да, я понимаю, что Python стремится быть как можно более простым, как завещал Эйнштейн: «все должно быть настолько простым, насколько это возможно, но не проще». Однако иногда Python всё же попадает в это «проще» чем надо, что может выливаться в проблемы.

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

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

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

Если мы напишем язык, который смогут использовать идиоты, в конце концов, только идиоты и будут его использовать. И да, это цена, которую придётся заплатить.


Закончу мысль довольно известной фразой: «Есть всего два типа языков программирования: те, на которые люди всё время ругаются, и те, которые никто не использует».

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

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

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

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

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

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

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

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

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

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

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

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

Определим, что должны уметь объекты для решения задачи «увеличить знания»:

  • Ученик должен уметь брать информацию и превращать ее в свои знания.

  • Учитель должен уметь учить группу учеников.

  • Данные могут представлять собой список знаний. Элементы будут извлекаться по индексу.

class Data:
    def __init__(self, *info):
        self.
info = list(info)   def __getitem__(self, i): return self.info[i]     class Teacher: def __init__(self): self.work = 0   def teach(self, info, *pupil): for i in pupil: i.take(info) self.work += 1     class Pupil: def __init__(self): self.knowledge = []   def take(self, info): self.knowledge.append(info)  

В класс Teacher также добавлено свойство экземпляров work, чтобы подсчитывать количество проделанной учителем работы.

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

>>> from test import *
>>> lesson = Data('class', 'object', 
... 'inheritance', 'polymorphism', 
... 'encapsulation')
>>> marIvanna = Teacher()
>>> vasy = Pupil()
>>> pety = Pupil()
>>> marIvanna.teach(lesson[2], vasy, pety)
>>> marIvanna.teach(lesson[0], pety)
>>> vasy.knowledge
['inheritance']
>>> pety. knowledge
['inheritance', 'class']

Может ли в этой программе ученик учиться без учителя? Если да, пусть научится чему-нибудь сам.

Добавьте в класс Pupil метод, позволяющий ученику случайно «забывать» какую-нибудь часть своих знаний.

Курс с примерами решений практических работ:
pdf-версия, android-приложение


Объектно-ориентированное программирование Python (ООП) — PYnative

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

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

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

  • Классы и объекты в Python : Вы поймете, как реализовать объектно-ориентированные программы, создав для создания классов и объектов.
  • Конструкторы в Python : узнайте, как создать конструктор для инициализации объекта в Python. создавать различные типы конструкторов.
  • Деструкторы Python для уничтожения объекта : Научитесь создавать деструктор в Python для освобождения других ресурсов, используемых объектом.
  • Инкапсуляция в Python : Научитесь реализовывать инкапсуляцию в Python с помощью класса. реализовать скрытие данных с использованием общедоступных, защищенных и частных членов
  • Полиморфизм в Python : научиться реализовывать полиморфизм в Python с помощью перегрузки функций, переопределения методов и перегрузки операторов.
  • Наследование в Python : Научитесь реализовывать наследование в Python. Кроме того, изучите типы наследования и MRO (порядок разрешения методов).
  • Переменные экземпляра Python : Научитесь создавать и получать доступ к переменным экземпляра. Измените значения переменных экземпляра. Поймите, как динамически мы можем добавлять или удалять переменные экземпляра из объекта
  • Методы экземпляра Python : научитесь создавать и вызывать методы экземпляра.
    Поймите, как динамически мы можем добавлять или удалять методы экземпляра из объекта
  • .
  • Переменные класса Python : Научитесь создавать, изменять и получать доступ к переменным класса. Поймите разницу между переменными экземпляра и переменными класса.
  • Метод класса Python : научитесь создавать и вызывать методы класса. Создайте метод класса, используя декоратор @classmethod и classmethod() функция
  • Статический метод Python : научитесь создавать и вызывать статические методы. Создайте статический метод с помощью декоратора @staticmethod и функции staticmethod()
  • Метод класса Python, статический метод и метод экземпляра : поймите разницу между всеми тремя методами класса
  • ООП-упражнение Python . Решите это упражнение, чтобы попрактиковаться и понять концепции ООП.

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

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

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

Объект имеет следующие две характеристики:

  • Атрибут
  • Поведение

Например, Автомобиль является объектом, так как он имеет следующие свойства:

  • название, цена, цвет как атрибуты
  • поломка, ускорение как поведение

Одним из важных аспектов ООП в Python является создание повторно используемого кода с использованием концепции наследования. Эта концепция также известна как DRY (не повторяйтесь).

Класс и объекты

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

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

Класс содержит свойства (атрибут) и действие (поведение) объекта. Свойства представляют собой переменные, а методы представляют собой действия. Следовательно, класс включает в себя как переменные, так и методы.

Класс и объекты Python

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

Подробнее : Классы и объекты в Python

Атрибуты и методы класса

При разработке класса мы используем переменные экземпляра и переменные класса.

В классе атрибуты могут быть разделены на две части:

  • Переменные экземпляра: Переменные экземпляра — это атрибуты, прикрепленные к экземпляру класса. Мы определяем переменные экземпляра в конструкторе (метод
    __init__()
    класса).
  • Переменные класса: переменная класса — это переменная, объявленная внутри класса, но вне любого метода экземпляра или __init()__ метод.

Внутри класса мы можем определить следующие три типа методов.

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

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

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

В Python используйте ключевое слово class для определения класса. В определении класса первой строкой является docstring, представляющая собой краткое описание класса.

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

Синтаксис

 класс classname:
    '''строка документации'''
   class_suite 
  • Строка документации : представляет описание класса . Это необязательно.
  • class_suite : класс набор содержит атрибуты и методы класса

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

 reference_variable = classname() 

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

 class Сотрудник:
    # переменные класса
    company_name = 'Компания ABC'

    # конструктор для инициализации объекта
    def __init__(я, имя, зарплата):
        # переменные экземпляра
        self.name = имя
        собственная зарплата = зарплата

    # метод экземпляра
    деф-шоу (я):
        print('Сотрудник:', self.name, self.salary, self.company_name)

# создаем первый объект
emp1 = Сотрудник ("Гарри", 12000)
emp1. show()

# создаем второй объект
emp2 = Сотрудник("Эмма", 10000)
emp2.show()
 

Выход :

 Сотрудник: Harry 12000 ABC Company
Сотрудник: Эмма 10000 ABC Company 
  • В приведенном выше примере мы создали класс с именем Сотрудник.
  • Далее мы определили два атрибута имя и зарплата.
  • Далее в методе __init__() мы инициализировали значение атрибутов. Этот метод вызывается сразу после создания объекта. Метод init инициализирует объект.
  • Наконец, из класса Employee мы создали два объекта, Эмму и Гарри.
  • Используя объект, мы можем получить доступ и изменить его атрибуты.
переменные и методы экземпляра

Конструкторы в Python

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

Основная цель конструктора — объявить и инициализировать переменные экземпляра. Он может принимать по крайней мере один аргумент равный 9.0054 сам . Метод __init()__ называется конструктором в Python. Другими словами, имя конструктора должно быть __ init __ (self) .

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

Подробнее :

  • Конструкторы в Python
  • деструкторов Python для уничтожения объекта

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

В Python инкапсуляция — это метод объединения данных и функций в единый объект. Например, класс A инкапсулирует все данные (методы и переменные). Инкапсуляция означает, что внутреннее представление объекта обычно скрыто от внешнего определения объекта.

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

Необходимость инкапсуляции

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

Прочтите полное руководство по инкапсуляции в Python .

Пример: инкапсуляция в Python

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

В Python у нас нет модификаторов доступа, таких как public, private и protected. Но мы можем добиться инкапсуляции, используя префикс single 9.0008 подчеркивание и двойное подчеркивание для управления доступом к переменной и методу в программе Python.

 класс Сотрудник:
    def __init__(я, имя, зарплата):
        # публичный член
        self.name = имя
        # закрытый участник
        # недоступно вне класса
        self. __salary = зарплата

    деф-шоу (я):
        print("Имя ", self.name, "и зарплата", self.__salary)

emp = Сотрудник("Джесса", 40000)
emp.show()

# доступ к зарплате вне класса
print(emp.__salary)
 

Выход :

 Имя Джесса и зарплата 40000
AttributeError: объект «Сотрудник» не имеет атрибута «__salary» 

В приведенном выше примере мы создаем класс с именем Сотрудник . В этом классе мы объявляем две переменные name и __salary . Мы можем заметить, что переменная name доступна, но __salary является частной переменной . Мы не можем получить к нему доступ извне класса. Если мы попытаемся получить к нему доступ, мы получим ошибку

Полиморфизм в Python

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

Полиморфизм происходит от греческих слов Poly (много) и morphism (формы). Полиморфизм определяет способность принимать различные формы.

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

Полиморфизм Python

Прочтите полное руководство по полиморфизму в Python .

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

Например, в приведенном ниже примере метод экземпляра calculate_area() создан как в классе Circle, так и в классе Rectangle. Таким образом, мы можем создать функцию, которая берет любой объект и вызывает метод calculate_area() объекта для реализации полиморфизма. Использование этого объекта может выполнять

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

 класс Круг:
    пи = 3,14

    def __init__(я, редиус):
        self. radius = редиус

    def calculate_area (я):
        print("Площадь круга:", self.pi * self.radius * self.radius)

класс Прямоугольник:
    def __init__(я, длина, ширина):
        собственная длина = длина
        собственная ширина = ширина

    def calculate_area (я):
        print("Площадь прямоугольника:", self.length * self.width)

# функция
площадь защиты (форма):
    # действие вызова
    shape.calculate_area()

# создать объект
круг = круг (5)
прямоугольник = прямоугольник (10, 5)

# вызов общей функции
площадь (окр)
площадь (прямая)
 

Выход :

 Площадь круга : 78,5
Площадь прямоугольника: 50 

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

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

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

Синтаксис

 класс Базовый класс:
  Тело базового класса
класс DerivedClass (базовый класс):
  Тело производного класса 

Читать полное руководство по Наследование в Python

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

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

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

 # Базовый класс
класс Транспортное средство:

    def __init__(я, имя, цвет, цена):
        self.name = имя
        self.color = цвет
        собственная цена = цена

    информация о защите (я):
        print(self.name, self.color, self. price)

# Дочерний класс
Класс Автомобиль(Автомобиль):

    def change_gear (я, нет):
        print(self.name, 'переключить передачу на номер', нет)

# Создать объект Car
car = Car('BMW X1', 'Черный', 35000)
автомобиль.информация()
car.change_gear(5)
 

Выход :

 BMW X1 Черный 35000
BMW X1 переключить передачу на номер 5 

Следующие шаги

  • Упражнение Python OOP

Все учебники Python по ООП:

Что такое Python Основы ООП

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

В этой статье мы обсудим основные принципы объектно-ориентированного программирования.

Класс

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

 

класс Крикет: идентификатор = 10 player = "Сачин Тендулкар" дисплей защиты (я): печать (self.id, self.player) print('Класс создан успешно')

Вывод

Ниже приведен вывод приведенного выше кода

 Класс создан успешно
 

Объект

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

Python рассматривает все как объекты, и большинство объектов имеют атрибуты и методы. Встроенный атрибут __doc__ всех функций возвращает строку документации, указанную в исходном коде функции.

Пример

Ниже приведен пример создания объекта —

 

class Cricket: идентификатор = 10 player = "Сачин Тендулкар" дисплей защиты (я): print("ID: %d \nPlayer: %s"%(self.id,self.player)) # Создать экземпляр crkt класса Cricket crct = сверчок () crct.display()

Вывод

Ниже приведен вывод вышеуказанного кода:

 ID: 10
Игрок: Сачин Тендулкар
 

Метод

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

Пример

В следующем примере определены два метода: plant() и animals(). Поскольку «Перо» является экземпляром объекта, они известны как методы экземпляра.

 

класс Программа: # Атрибуты экземпляра def __init__(я, имя, возраст): self.name = имя возраст = возраст # Метод экземпляра Завод по определению (я, эвкалипт): вернуть "{} растения {}".format(self.name, эвкалипт) определение животных (я): вернуть "{} животных".format(self.name) # создание экземпляра объекта Перо = Программа ("Перо", 10) # вызов методов экземпляра print(Pen.plant("'Кодирование'")) print(Pen.animals())

Вывод

Ниже приведен вывод вышеуказанного кода —

 Загонные растения «Кодирование»
Загонные животные
 

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

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

Пример

Ниже приведен пример наследования в Python

 

# Родительский класс класс Животное: защита __init__(сам): print("Животное там") определение WhatIstheClass (я): Печать("Животное") Def Run (я): print("Работает на скорости") # Дочерний класс класс Лев(Животное): защита __init__(сам): # вызов функции super() супер(). __инит__() print("Лев там") определение WhatIstheClass (я): печать("Лев") деф запустить (самостоятельно): print("Работает на скорости") синий = Лев () blu.WhatIstheClass() синий.Выполнить() blu.run()

Output

В приведенном выше коде мы установили два класса: Animal (родительский класс) и Lion (дочерний класс). Функции родительского класса наследуются дочерним классом. Это видно из метода Run().

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

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

 Животное здесь
Лев там
Лев
Работает на скорости
Работает на скорости
 

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

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

Пример

Ниже приведен пример инкапсуляции данных в Python —

 

class Sports: защита __init__(сам): self.__sportsName = "Крикет" деф игра(я): print("Игра: {}".format(self.__sportsName)) def Player_Name(я, игрок): self.__sportsName = игрок с = Спорт() с.игра() # изменение спортивного названия s.__sportsName = 'Хоккей' с.игра() # используя функцию установки s.Player_Name('Хоккей') с.игра()

Вывод

Спортивный класс определен в приведенном выше коде. Название игры Sports сохраняется с помощью метода __init__(). Посмотрите на код ниже

 s.__sportsName = 'Хоккей'
 

Здесь мы попытались изменить значение __sportsName вне класса. Поскольку __sportsName является закрытой переменной, выходные данные не отражают эту модификацию. Мы должны использовать функцию-установщик Player Name(), которая принимает в качестве параметра sportsName, чтобы настроить значение.

 Игра: Крикет
Игра: Крикет
Игра: Хоккей
 

Полиморфизм

«Поли» и «морфы» — два слова, составляющие полиморфизм. Слова «поли» и «морф» означают «множество» и «форма» соответственно. Под полиморфизмом мы понимаем, что одно и то же действие может выполняться различными способами.

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

Пример

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

класса Lion: Защита Рев(я): print("Лев может рычать") Защита Барка (самостоятельно): print("Лев не может лаять") класс Собака: Защита Рев(я): print("Собака не может рычать") Защита Барка (самостоятельно): print("Собака может лаять") # одинаковые качества определение sound_test (млекопитающее): млекопитающее.