что такое абстрактный класс в python
Абстрактный класс ABC
Абстрактный класс – класс, содержащий один и более абстрактных методов.
Абстрактный метод – метод, который объявлен, но не реализован.
Абстрактный класс не может быть инстанциирован (создан его экземпляр). Нужно наследовать этот класс и реализовать (переопределить) все абстрактные методы, и только после этого можно создавать экземпляры такого наследника.
В Python нет синтаксической поддержки абстрактных классов, но есть встроенный модуль abc (расшифровка – abstract base classes), который помогает проектировать абстрактные сущности.
Абстрактный класс наследуют от ABC (Python 3.4+) или указывают метакласс ABCMeta (для Python 3.0+):
Любой из вариантов работает, первый современнее и короче. На данном этапе мы можем создавать объекты этих классов, потому что в них пока не абстрактных методов. Добавим:
Кроме обычных методов, абстрактными можно обозначить и статические, классовые методы, а также свойства:
Абстрактные классы широко фигурируют в ООП, часто всплывают в шаблонах проектирования. Они говорят, что общий интерфейс уже обозначен, но этот класс еще не предназначен для использования, кроме как для наследования от него конкретных потомков.
Формально говоря, абстрактные классы для Python не являются чем-то необходимым в силу динамичности языка. Если мы выкинем все упоминания абстрактности классов и методов из рабочего кода, он продолжит работать, как и ранее. Абстрактные классы нужны на этапе проектирования или расширения кода, чтобы обеспечивать «правильные» взаимодействия новых классов, защищая от создания экземпляров абстрактных классов. Важно помнить, что эта защита срабатывает на этапе выполнения программы, а не компиляции, как в языках Java, C++ или C#!
Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈
Понимание абстракции в Python
В этом руководстве мы обсудим концепцию абстракции в Python для подхода объектно-ориентированного программирования.
По сути, Abstraction фокусируется на сокрытии внутренних реализаций процесса или метода от пользователя. Таким образом, пользователь знает, что он делает, но не знает, как выполняется работа.
Что такое абстракция в Python?
Например, люди не думают об автомобиле как о совокупности тысяч отдельных деталей. Вместо этого они видят в нем четко определенный объект со своим уникальным поведением. Эта абстракция позволяет людям управлять автомобилем, не зная о сложности деталей, из которых он состоит. Они могут игнорировать детали работы трансмиссии двигателя и тормозных систем. Вместо этого они могут использовать объект в целом.
Мощный способ управления абстракцией — использование иерархической классификации. Это позволяет нам наслоить семантику сложных систем, разбивая их на более управляемые части. Снаружи автомобиль представляет собой единый объект. Оказавшись внутри, вы видите, что автомобиль состоит из нескольких подсистем: рулевого управления, тормозов, аудиосистемы, ремней безопасности и т. д. В свою очередь, каждая из этих подсистем состоит из более мелких блоков.
Дело в том, что мы управляем автомобилем (или любой другой сложной системы) с помощью иерархических абстракций.
Это также может быть применено к компьютерным программам, использующим концепции ООП. В этом суть объектно-ориентированного программирования.
Абстрактные классы и методы в Python
Здесь abs_class — это абстрактный класс, внутри которого могут быть определены абстрактные методы или любые другие методы.
В качестве свойства абстрактные классы могут иметь любое количество абстрактных методов, сосуществующих с любым количеством других методов. Например, мы можем видеть ниже.
Здесь method() — обычный метод, тогда как Abs_method() — абстрактный метод, реализующий @abstractmethod из модуля abc.
Пример
Теперь, когда мы знаем об абстрактных классах и методах, давайте взглянем на пример.
После того, как пользователь создает объекты из классов test_class и example_class и вызывает метод task() для обоих из них, в игру вступают скрытые определения методов task() внутри обоих классов. Эти определения скрыты от пользователя. Абстрактный метод task() из абстрактного класса Absclass фактически никогда не вызывается.
Но когда метод print() вызывается как для test_obj, так и для example_obj, вызывается метод print() Absclass, поскольку это не абстрактный метод.
Абстракция в Python – простое объяснение
Абстракция используется, чтобы скрыть внутренние характеристики функции от пользователей. Пользователи взаимодействуют только с базовой реализацией функции, но внутренняя работа скрыта. Пользователь знаком с тем, «что делает функция», но не знает, «как она работает».
Проще говоря, мы все пользуемся смартфоном и хорошо знакомы с его функциями, такими как камера, диктофон, набор номера и т. д., но мы не знаем, как эти операции выполняются в фоновом режиме. Возьмем другой пример – когда мы используем пульт от телевизора для увеличения громкости. Мы не знаем, как нажатие клавиши увеличивает громкость телевизора. Известно только, что нужно нажимать кнопку «+», чтобы увеличить громкость.
Это именно та абстракция, которая работает в объектно-ориентированной концепции.
Почему важна абстракция?
В Python абстракция используется, чтобы скрыть незначимые данные или класс, чтобы уменьшить сложность. Это также повышает эффективность приложения. Далее мы узнаем, как добиться абстракции в Python.
Классы абстракции в Python
Абстракция в Python может быть достигнута с помощью абстрактных классов и интерфейсов.
Класс, состоящий из одного или нескольких абстрактных методов, называется абстрактным классом. Абстрактные методы не содержат своей реализации. Абстрактный класс может быть унаследован подклассом, а абстрактный метод получает свое определение в подклассе. Классы абстракции должны быть прототипом другого класса. Абстрактный класс может быть полезен при разработке больших функций, а также для предоставления стандартного интерфейса для различных реализаций компонентов. Python предоставляет модуль abc для использования абстракции в программе Python. Рассмотрим следующий синтаксис.
Мы импортируем класс ABC из модуля abc.
Абстрактные базовые классы
Абстрактный базовый класс – это общая прикладная программа интерфейса для набора подклассов. Его может использовать сторонний поставщик, который предоставит такие реализации, как плагины. Это также полезно, когда мы работаем с большой базой кода, трудно запомнить все классы.
Работа абстрактных классов
В отличие от других языков высокого уровня, Python не предоставляет самого абстрактного класса. Нам нужно импортировать модуль abc, который обеспечивает основу для определения абстрактных базовых классов (ABC). ABC работает, декорируя методы базового класса как абстрактные. Он регистрирует конкретные классы как реализацию абстрактной базы. Мы используем @abstractmethod декоратор для определения абстрактного метода или, если мы не предоставляем определение методу, он автоматически становится абстрактным методом. Давайте разберемся в следующем примере.
В приведенном выше коде мы импортировали модуль abc для создания абстрактного базового класса. Мы создали класс Car, который унаследовал класс ABC, и определили абстрактный метод с именем mileage(). Затем мы унаследовали базовый класс от трех разных подклассов и по-разному реализовали абстрактный метод. Мы создали объекты для вызова абстрактного метода.
Разберемся еще на одном примере.
В приведенном выше коде мы определили абстрактный базовый класс с именем Polygon, а также определили абстрактный метод. Этот базовый класс наследуется различными подклассами. Мы реализовали абстрактный метод в каждом подклассе. Мы создали объект подклассов и вызываем метод side(). В игру вступают скрытые реализации метода side() внутри каждого подкласса. Абстрактный метод side(), определенный в абстрактном классе, никогда не вызывается.
Что следует помнить
Ниже приведены моменты, которые мы должны помнить об абстрактном базовом классе в Python:
Абстракция необходима для сокрытия подробных функций от пользователей. Мы рассмотрели все основные концепции абстракции в Python.
Абстрактные классы и интерфейсы в Питоне
Абстрактные базовые классы и интерфейсы — близкие по назначению и смыслу сущности. Как первые, так и вторые представляют собой своеобразный способ документирования кода и помогают ограничить (decouple) взаимодействие отдельных абстракций в программе (классов).
Питон — очень гибкий язык. Одна из граней этой гибкости — возможности, предоставляемые метапрограммированием. И хотя в ядре языка абстрактные классы и интерфейсы не представлены, первые были реализованы в стандартном модуле abc, вторые — в проекте Zope (модуль zope.interfaces).
Нет смысла одновременно использовать и то и другое, и поэтому каждый программист должен определить для себя, какой инструмент использовать при проектировании приложений.
2 Абстрактные базовые классы (abс)
Начиная с версии языка 2.6 в стандартную библиотеку включается модуль abc, добавляющий в язык абстрактные базовые классы (далее АБК).
АБК позволяют определить класс, указав при этом, какие методы или свойства обязательно переопределить в классах-наследниках:
Таким образом, если мы хотим использовать в коде объект, обладающий возможностью перемещения и определенной скоростью, то следует использовать класс Movable в качестве одного из базовых классов.
Наличие необходимых методов и атрибутов объекта теперь гарантируется наличием АБК среди предков класса:
Видно, что понятие АБК хорошо вписывается в иерархию наследования классов, использовать их легко, а реализация, если заглянуть в исходный код модуля abc, очень проста. Абстрактные классы используются в стандартных модулях collections и number, задавая необходимые для определения методы пользовательских
классов-наследников.
Подробности и соображения по поводу использования АБК можно найти в PEP 3119
(http://www.python.org/dev/peps/pep-3119/).
3 Интерфейсы (zope.interfaces)
Реализация проекта Zope в работе над Zope3 решила сделать акцент на компонентной архитектуре; фреймворк превратился в набор практически независимых компонент. Клей, соединяющий компоненты — интерфейсы и основывающиеся на них адаптеры.
Модуль zope.interfaces — результат этой работы.
В простейшем случае использвание интерфейсов напоминает примерение АБК:
В интерфейсе декларативно показывается, какие атрибуты и методы должны быть у объекта. Причем класс реализует (implements) интерфейс, а объект класса — предоставляет (provides). Следует обратить внимание на разницу между этими понятиями!
«Реализация» чем-либо интерфейса означает, что только «производимая» сущность будет обладать необходимыми свойствами; а «предоставление» интерфейса говорит о конкретных возможностях оцениваемой сущности. Соответственно, в Питоне классы, кстати, могут как реализовывать, так и предоставлять интерфейс.
На самом деле декларация implement(IVehicle) — условность; просто обещание, что данный класс и его объекты ведут себя именно таким образом. Никаких реальных проверок проводиться не будет
Видно, что в простейших случаях интерфейсы только усложняют код, как, впрочем, и АБК
Компонентная архитектура Zope включает еще одно важное понятие — адаптеры. Вообще говоря, это простой шаблон проектирования, корректирующий один класс для использования где-то, где требуется иной комплект методов и атрибутов. Итак,
4 Адаптеры
Предположим, что имеется пара классов, Guest и Desk. Определим интерфейсы к ним, плюс класс, реализующий интерфейс Guest:
Адаптер должен учесть анонимного гостя, зарегистрировав в списке имен:
Существует реестр, который ведет учет адаптеров по интерфейсам. Благодаря ему можно получить адаптер, передав в вызов класса-интерфейса адаптируемый объект. Если адаптер не зарегистрирован, то вернется второй аргумент интерфейса:
Такую инфраструктуру удобно использовать для разделения кода на компоненты и их связывания.
Один из ярчайших примеров использования такого подхода помимо самого Zope — сетевой фреймворк Twisted, где изрядная часть архитектуры опирается на интерфейсы из zope.interfaces.
5 Вывод
При ближайшем рассмотрении оказывается, что интерфейсы и абстрактные базовые классы — разные вещи.
Абстрактные классы в основном жестко задают обязательную интерфейсную часть. Проверка объекта на соответствие интерфейсу абстрактного класса проверяется при помощи встроенной функции isinstance; класса — issubclass. Абстрактный базовый класс должен включаться в иерархию в виде базового класса либо mixin`а.
Минусом можно считать семантику проверок issubclass, isinstance, которые пересекаются с обычными классами (их иерархией наследования). На АБК не выстраивается никаких допонительных абстракций.
Интерфейсы — сущность декларативная, они не ставят никаких рамок; просто утверждается, что класс реализует, а его объект предоставляет интерфейс. Семантически утверждения implementedBy, providedBy являются более корректными. На такой простой базе удобно выстраивать компонентную архитектуру при помощи адапетров и других производных сущностей, что и делают крупные фреймворки Zope и Twisted.
Надо понимать, что использование обоих инструментов имеет смысл только при построении и использовании сравнительно крупных ООП-систем — фреймворков и библиотек, в малых программах они могут только запутать и усложнить код код лишними абстракциями.
Абстрактные классы в Python
Абстрактный класс можно рассматривать как план для других классов, он позволяет вам создавать набор методов, которые должны быть созданы в любых дочерних классах, созданных из вашего абстрактного класса. Класс, который содержит один или абстрактный метод, называется абстрактным классом. Абстрактный метод — это метод, который имеет объявление, но не имеет никакой реализации. Абстрактные классы не могут быть созданы, и для этого нужны подклассы для реализации тех абстрактных методов, которые определены в абстрактных классах. В то время как мы разрабатываем большие функциональные блоки, мы используем абстрактный класс. Когда мы хотим предоставить общую реализованную функциональность для всех реализаций компонента, мы используем абстрактный класс. Абстрактные классы позволяют частично реализовать классы, когда он полностью реализует все методы в классе, тогда это называется интерфейсом.
Зачем использовать абстрактные базовые классы:
Абстрактные классы позволяют предоставлять функциональность по умолчанию для подклассов. По сравнению с интерфейсами абстрактные классы могут иметь реализацию. Определив абстрактный базовый класс, вы можете определить общий интерфейс прикладных программ (API) для набора подклассов. Эта возможность особенно полезна в ситуациях, когда сторонние разработчики предоставляют реализацию, например, с помощью плагинов в приложении, но также могут помочь вам при работе в большой команде или с большой кодовой базой, где все классы хранятся в вашем приложении. Голова при этом сложная или невозможная.
Код 1:
# Показ программы Python
# абстрактная работа базового класса