Python: Погружаясь в классы
2026-02-26 18:23 Diff

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

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

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

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

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

Рассмотрим наследование на примере структуры HTML. Каждый тег в HTML по своему уникален. Также у них есть общие атрибуты и некоторые другие характеристики. Попробуем отобразить это с помощью иерархии классов:

В этом коде мы определили базовый класс HTMLElement, который представляет общую структуру HTML-элемента. Методы set_attribute и get_attribute устанавливают и получают атрибуты HTML-элемента, а set_text_content и get_text_content работают с текстовым содержимым элемента.

Теперь создадим подкласс HTMLAnchorElement, представляющий тег «a» в HTML, наследуя его от класса HTMLElement:

Здесь мы определили класс HTMLAnchorElement, который наследует все атрибуты и методы класса HTMLElement. Мы также добавили метод __str__, который возвращает строковое представление HTML-элемента.

Наследование записывается так: A(B). Эта запись означает, что класс A наследует класс B.

Теперь посмотрим, как работает наследование:

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

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

Цепочка наследования

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

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

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

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

Оператор проверки типа

В Python можно использовать оператор isinstance() для проверки принадлежности объекта к определенному классу, учитывая при этом наследование:

Здесь мы создали объект anchor класса HTMLAnchorElement и проверили, является ли он экземпляром класса HTMLElement. Поскольку HTMLAnchorElement наследуется от HTMLElement, функция isinstance() возвращает True.

Для проверки точного класса объекта, мы можем использовать функцию type():

Здесь мы используем функцию type(), чтобы проверить, что класс объекта anchor точно является HTMLAnchorElement.

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

Выводы

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