Зарегистрируйтесь, чтобы продолжить обучение

Код, который убивает полиморфизм Python: Полиморфизм

В этом уроке мы разберем, как некоторые подходы могут подорвать идею полиморфизма в наших программах. Мы разберем следующие популярные способы нарушения полиморфизма: формирование объектов, проверка типов и слишком много условий.

Формирование объектов

Изучим функцию ниже. Можно ли считать ее полиморфной?

class EmailSender:
    def send(self, email, message):
        return f"Sending '{message}' to {email}"


class User:
    def __init__(self, email):
        self.email = email

    def get_email(self):
        return self.email


def say_hi_by_email(user):
    sender = EmailSender()
    return sender.send(user.get_email(), "Hi!")

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

Такой код демонстрирует важную идею: полиморфизм возможен, когда объект передается в функцию извне, а не создается внутри нее.

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

Рассмотрим еще один пример. Есть ли полиморфизм в следующем коде?

class User:
    def __init__(self, name):
        self.name = name


class Guest:
    pass


def say_hi(user):
    if isinstance(user, User):
        return f"Hello, {user.name}!"
    elif isinstance(user, Guest):
        return "Hello, guest!"
    else:
        return "Who are you?"

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

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

В подобной ситуации есть два подхода к решению:

  • Перенести всю логику внутрь классов. Тогда код функции say_hi будет выглядеть так: return user.say_hi(). Но следует быть осторожным. С этим подходом легко получить «божественный объект», который управляет всем
  • Второй способ — введение нового интерфейса в виде методов is_user и is_guest:
def say_hi(user):
    if user.is_user():
        return f"Hello, {user.name}!"
    elif user.is_guest():
        return "Hello, guest!"
    else:
        return "Who are you?"

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

Выводы

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

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

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

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

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

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

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

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

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff