Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Наследование Python: Погружаясь в классы

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

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

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

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

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

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

class HTMLElement:
    def __init__(self, attributes=None):
        self.attributes = attributes if attributes else {}
        self.body = None

    def set_attribute(self, key, value):
        self.attributes[key] = value

    def get_attribute(self, key):
        return self.attributes.get(key)

    def set_text_content(self, body):
        self.body = body

    def get_text_content(self):
        return self.body

    def stringify_attributes(self):
        # Строим: key="value" key2="value2"
        pass

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

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

class HTMLAnchorElement(HTMLElement):
    def __str__(self):
        attr_line = self.stringify_attributes()
        body = self.get_text_content()
        return f'<a{attr_line}>{body}</a>'

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

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

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

# Инициализация экземпляра суперкласса
anchor = HTMLAnchorElement({'href': '<https://ru.hexlet.io>'})
anchor.set_text_content('Hexlet')
print(f"Anchor: { anchor }") # __str__ вызывается автоматически
# => Anchor: <a href="<https://ru.hexlet.io>">Hexlet</a>

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

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

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

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

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

class D: pass
class C(D): pass
class B(C, D): pass
class A(B): pass

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

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

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

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

anchor = HTMLAnchorElement({'href': '<https://ru.hexlet.io>'})
anchor.set_text_content('Hexlet')
print(isinstance(anchor, HTMLElement))  # => True

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

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

print(type(anchor) == HTMLAnchorElement)      # => True

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

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

Выводы

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


Дополнительные материалы

  1. Наследование (Wiki)

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

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

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
Обучитесь разработке бэкенда сайтов и веб-приложений — серверной части, которая отвечает за логику и базы данных
10 месяцев
с нуля
Старт 28 ноября

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»