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

Полиморфизм в ООП — что это?

Если говорить буквально, то слово polymorphism означает «множество форм».

Полиморфизм в «Пайтон»

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

Пример № 1

Хорошо известно, что оператор “+” нередко применяют в программах, написанных на Python. Но использовать этот оператор можно по-разному.

Если мы говорим о целочисленных типах данных, то мы применяем “+” в целях сложения операндов:

number1 = 1
number2 = 2
print(number1 + number2)

Такая программа выведет на экран цифру 3. Элементарно, Ватсон!

Однако применять “+” можно и для конкатенации строк:

string1 = "Hello,"
string2 = "Otus!"
print(string1+" "+string2)

Результат очевиден и здесь:

Hello Otus!

Какой же вывод можно сделать из вышесказанного? У нас существует единственный оператор “+”, который способен выполнять разные операции для разных типов данных. Это является одним из наиболее простых примеров полиморфизма на «Пайтон».

Пример № 2

В языке Python существуют функции, способные принимать аргументы различных типов. Пример такой функции — len(). Она способна принимать разные типы данных. Работает это следующим образом:

print(len("ООП-программирование"))
print(len(["Python", "Java", "C#", "Scala", "C++"]))
print(len({"Где изучить?": "В Otus", "Как проходят занятия?": "Онлайн"}))

Вывод будет необычен, но если разобраться, то все просто:

20
 5
 2

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

  • посчитала количество букв в слове «Программирование»;
  • посчитала количество слов в списке;
  • посчитала количество ключей в словаре.
Полиморфизм в «Пайтон»

Пример № 3

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

Ниже — пример такого полиморфизма в методах класса:

Полиморфизм в «Пайтон»

Смотрим вывод в консоль:

Мяу!
Я кот. Меня зовут Васька. Мне 2 года.
Мяу!
Гав!
Я собака. Меня зовут Мухтар. Мне 3 года.
Гав!

У нас создано 2 класса: Cat и Dog. У этих классов структура похожа, плюс они имеют методы с одинаковыми именами:

  • make_sound();
  • info().

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

Пример № 4

Как и в прочих языках программирования, в «Питоне» классы-потомки способны выполнять наследование методов и атрибутов родительского класса. То есть у нас существует возможность переопределить ряд methods и attributes, сделав это для того, чтобы они соответствовали классу-потомку. Данное поведение называют переопределением (overriding). И благодаря наличию полиморфизма мы можем получать доступ к переопределенным methods и attributes, имеющим такое же имя, как и в parent class.

Пример такого переопределения ниже:

from math import pi
class Shape:
    def __init__(self, name):
        self.name = name
    def area(self):
        pass
    def fact(self):
        return "Я - двумерная фигура"
    def __str__(self):
        return self.name
class Square(Shape):
    def __init__(self, length):
        super().__init__("Квадрат")
        self.length = length
    def area(self):
        return self.length**2
    def fact(self):
        return "Любой угол квадрата равен 90 градусов."
class Circle(Shape):
    def __init__(self, radius):
        super().__init__("Круг")
        self.radius = radius
    def area(self):
        return pi*self.radius**2
a = Square(5)
b = Circle(8)
print(b)
print(b.fact())
print(a.fact())
print(b.area())

Смотрим на вывод программы:

Круг
Я - двумерная фигура
Любой угол квадрата равняется 90 градусам.
201.06192982974676

В работе кода мы использовали методы __str__() — они не были переопределены в дочерних классах и применяются непосредственно из класса-родителя. То есть интерпретатор «Пайтона» автоматически распознал, что метод fact() для объекта a (class Square) является переопределенным. В результате применяется тот метод, который был определен в классе-потомке.

В это же самое время, метод fact() для объекта переопределенным не является, в результате чего применяется метод с таким же именем из parent class (Shape).

Полиморфизм в «Пайтон»

Важно отметить, что в «Питоне» не поддерживается такой вариант method overriding, как создание методов с тем же самым именем, однако с различными типами аргументов.

Надеемся, теперь вы знаете достаточно, чтобы пройти собеседование. Если же интересуют подробности полиморфизма в Java, можете почитать, к примеру, эту статью. Если же хотите освоить какой-нибудь из вышеупомянутых языков программирования на профессиональном уровне, добро пожаловать на курсы в Otus!

Полиморфизм в «Пайтон»
Полиморфизм в «Пайтон»

Источник — https://www.programiz.com/python-programming/polymorphism.