Полиморфизм является возможностью использовать один и тот же интерфейс для различных базовых форм, таких как типы данных или классы. Это позволяет функции использовать объекты разных типов в разные моменты времени.
Для объектно-ориентированного программирования в Python, это означает, что конкретный объект, принадлежащий к определенному классу может быть использован таким же образом, как если бы это был другой объект, принадлежащий к другому классу.
Полиморфизм обеспечивает гибкость и слабую связь с тем, что код может быть расширен и легко поддерживаться в течение долгого времени.
Этот учебник будет описывать применение полиморфизма на классы в Python.
Полиморфизм является важной особенностью определения класса в Python, который используется, когда обычно называют методы по классам или подклассам. Это позволяет функции использовать объекты любого из этих полиморфных классов без необходимости знать о различиях этих классов.
Полиморфизм в Python использует язык программирования по утиной типизации. Термин «утиная типизация» происходит от цитаты писателя Джеймс Уитком Рили: «Когда я вижу птицу, которая ходит как утка и плавает как утка и крякает как утка, я называю эту птицу уткой.» Компьютерный инженер Алекс Мартелл в сообщении на конференции comp.lang.python, использование утиной типизации касается установления пригодности объекта для конкретной цели. При использовании нормальной печати эта пригодность определяется типом только объекта, но с уткой собрав наличие методов и свойств, используется для определения пригодности, а не фактический тип рассматриваемого объекта. То есть, вы проверяете крякает ли объект как утка и ходит как утка, а не спрашиваете объект, утка ли это.
Когда несколько классов имеют одни и те же имена методов, но различные реализации для этих же методов, классы являются полиморфными. Функция будет иметь возможность оценить эти полиморфные методы, не зная, какие классы вызываются.
Для того, чтобы использовать полиморфизм, мы собираемся создать два различных класса для использования с двумя различными объектами. Каждый из этих различных классов должен иметь интерфейс, в общем, так что они могут быть использованы полиморфно, поэтому мы дадим им методы, которые отличаются, но имеют такое же имя.
Мы создадим класс Shark
и класс Clownfish
, каждый из которых будет определять методы swim()
, swim_backwards()
и skeleton()
.
class Shark(): def swim(self): print("Акула плавает.") def swim_backwards(self): print("Акула не может плыть задом, но может плыть вниз.") def skeleton(self): print("Скелет акулы состоит из хрящей.") class Clownfish(): def swim(self): print("Рыба плавает.") def swim_backwards(self): print("Рыба не может плыть назад.") def skeleton(self): print("Скелет рыбы состоит из костей.")
В приведенном выше коде, классы Shark
и Clownfish
имеют три метода с тем же общем именем. Тем не менее, каждая функциональная возможность этих методов различны для каждого класса.
Давайте создадим экземпляр этих классов на два объекта:
... sammy = Shark() sammy.skeleton() casey = Clownfish() casey.skeleton()
При запуске программы на python с командой polymorphic_fish.py
, мы можем видеть, что каждый объект ведет себя, как и ожидалось:
Скелет акулы состоит из хрящей. Скелет рыб состоит из костей.
Теперь, когда у нас есть два объекта, которые используют общий интерфейс, можно использовать два объекта таким же образом, независимо от их отдельных видов.
Для того, чтобы показать, как Python может использовать каждый из этих различных типов классов, мы можем сначала создать цикл for, который перебирает объекты tuple. Тогда мы можем вызывать методы, не заботясь о том, какой тип класса имеет каждый объект. Мы будем предполагать, что эти методы действительно существуют в каждом классе.
... 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()
.
При запуске программы, вывод будет выглядеть следующим образом:
Акула плавает. Акула не может плыть задом, но может плыть вниз. Скелет акулы состоит из хрящей. Рыба плавает. Рыба не может плыть назад. Скелет рыб состоит из костей.
Цикл for повторяет сначала sammy
из класса Shark
, а потом объект casey
из класса Clownfish
, поэтому мы видим методы, относящихся к классу Shark
, и к классу Clownfish
.
Это показывает, что Python использует эти методы в пути, не зная и не заботясь о точности, к какому типу класса относиться каждый из этих объектов. То есть, используя эти методы полиморфным образом.
Мы также можем создать функцию, которая может принимать любой объект, что позволяет полиморфизм.
Давайте создадим функцию с именем in_the_pacific()
которая принимает в качестве объекта fish
. Хотя мы используем имя fish
, любой экземпляр объекта будет в состоянии назвать в этой функции:
… def in_the_pacific(fish):
Далее, мы дадим функции что – то делать, что использует объект fish
. В этом случае мы будем вызывать метод swim()
, который определен в двух классах Shark
и Clownfish
:
... def in_the_pacific(fish): fish.swim()
Далее, мы создадим экземпляр обоих классов Shark
и Clownfish
, если у нас их нет еще. Теперь, мы можем вызвать, используя ту же функцию in_the_pacific()
:
... def in_the_pacific(fish): fish.swim() sammy = Shark() casey = Clownfish() in_the_pacific(sammy) in_the_pacific(casey)
При запуске программы, вывод будет выглядеть следующим образом:
Акула плавает. Рыба плавает.
Даже если мы прошли случайный объект ( fish
) в функцию in_the_pacific()
при определении его, мы все еще были в состоянии эффективно использовать его для конкретизации из классов Shark
и Clownfish
. Объект casey
вызвал метод swim()
, определенный в классе Clownfish
, и объект sammy
, вызываемый метод swim()
, определенный в классе Shark
.
Предоставляя различные объекты, использовать функции и методы аналогичным образом с помощью полиморфизма, что обеспечивает использование этой функции в Python большую гибкость и расширяемость вашего объектно-ориентированного кода.