Как применить полиморфизм к классам в Python 3

Вступление

Polymorphism - это возможность использовать один и тот же интерфейс для различных базовых форм, таких какdata types илиclasses. Это позволяетfunctions использовать сущности разных типов в разное время.

Для объектно-ориентированного программирования в Python это означает, что конкретный объект, принадлежащий определенному классу, можно использовать так же, как если бы это был другой объект, принадлежащий другому классу.

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

Этот урок будет проходить через применение полиморфизма к классам в Python.

Что такое полиморфизм?

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

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

duck typing в Python, особый случай динамической типизации, использует методы, характерные для полиморфизма, включаяlate binding иdynamic dispatch. Термин «типирование утки» происходит от цитаты писателя Джеймса Уиткомба Райли: «Когда я вижу птицу, которая ходит как утка и плавает, как утка, и крякает, как утка, я называю эту птицу уткой». компьютерный инженер Алекс Мартелли в сообщении для новостной группы comp.lang.python говорит, что использование утиной типизации связано с установлением пригодности объекта для определенной цели. При использовании обычной типизации эта пригодность определяется только типом объекта, но при типизации утки наличие методов и свойств используются для определения пригодности, а не фактического типа рассматриваемого объекта. Другими словами, вы проверяете, крякает ли объект как утка и ходит как утка, вместо того, чтобы спрашивать, утка ли объектis.

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

Создание полиморфных классов

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

Мы создадим классShark и классClownfish, каждый из которых будет определять методы дляswim(),swim_backwards() иskeleton().

polymorphic_fish.py

class Shark():
    def swim(self):
        print("The shark is swimming.")

    def swim_backwards(self):
        print("The shark cannot swim backwards, but can sink backwards.")

    def skeleton(self):
        print("The shark's skeleton is made of cartilage.")


class Clownfish():
    def swim(self):
        print("The clownfish is swimming.")

    def swim_backwards(self):
        print("The clownfish can swim backwards.")

    def skeleton(self):
        print("The clownfish's skeleton is made of bone.")

В приведенном выше коде классыShark иClownfish имеют три общих метода с одинаковым именем. Тем не менее, каждая из функций этих методов отличается для каждого класса.

Давайте создадим эти классы в виде двух объектов:

polymorphic_fish.py

...
sammy = Shark()
sammy.skeleton()

casey = Clownfish()
casey.skeleton()

Когда мы запускаем программу с командойpython polymorphic_fish.py, мы видим, что каждый объект ведет себя так, как ожидалось:

OutputThe shark's skeleton is made of cartilage.
The clownfish's skeleton is made of bone.

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

Полиморфизм с методами класса

Чтобы показать, как Python может одинаково использовать каждый из этих разных типов классов, мы можем сначала создатьfor loop, который выполняет итерацию черезtuple объектов. Затем мы можем вызывать методы, не заботясь о том, какой тип класса у каждого объекта. Мы будем только предполагать, что эти методы действительно существуют в каждом классе.

polymorphic_fish.py

...
sammy = Shark()

casey = Clownfish()

for fish in (sammy, casey):
    fish.swim()
    fish.swim_backwards()
    fish.skeleton()

У нас есть два объекта:sammy классаShark иcasey классаClownfish. Наш циклfor проходит по этим объектам, вызывая для каждого из них методыswim(),swim_backwards() иskeleton().

Когда мы запустим программу, результат будет следующим:

OutputThe shark is swimming.
The shark cannot swim backwards, but can sink backwards.
The shark's skeleton is made of cartilage.
The clownfish is swimming.
The clownfish can swim backwards.
The clownfish's skeleton is made of bone.

Циклfor повторяется сначала через экземплярsammy классаShark, затем через объектcasey классаClownfish, поэтому мы видим методы, связанные с сначала классShark, затем классClownfish.

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

Полиморфизм с функцией

Мы также можем создать функцию, которая может принимать любой объект с учетом полиморфизма.

Давайте создадим функцию с именемin_the_pacific(), которая принимает объект, который мы можем вызватьfish. Хотя мы используем имяfish, в этой функции можно будет вызвать любой экземпляр объекта:

polymorphic_fish.py

…
def in_the_pacific(fish):

Затем мы дадим функции что-то сделать, чтобы использовать переданный ей объектfish. В этом случае мы вызовем методыswim(), каждый из которых определен в двух классахShark иClownfish:

polymorphic_fish.py

...
def in_the_pacific(fish):
    fish.swim()

Затем мы создадим экземпляры классовShark иClownfish, если у нас их еще нет. С ними мы можем вызвать их действие, используя ту же функциюin_the_pacific():

polymorphic_fish.py

...
def in_the_pacific(fish):
    fish.swim()

sammy = Shark()

casey = Clownfish()

in_the_pacific(sammy)
in_the_pacific(casey)

Когда мы запустим программу, результат будет следующим:

OutputThe shark is swimming.
The clownfish is swimming.

Несмотря на то, что мы передали случайный объект (fish) в функциюin_the_pacific() при его определении, мы по-прежнему могли эффективно использовать его для создания экземпляров классовShark иClownfish . Объектcasey вызвал методswim(), определенный в классеClownfish, а объектsammy вызвал методswim(), определенный в классеShark .

Заключение

Позволяя различным объектам одинаково использовать функции и методы посредством полиморфизма, использование этой функции Python обеспечивает большую гибкость и расширяемость вашего объектно-ориентированного кода.