Полиморфизм в Python
| Введение | |
| Пример | |
| Duck Typing | |
| Далее по теме |
Введение
Попытаюсь разобраться, что подразумевают под полиморфизмом в Python.
Пока что примеры, которые я видел это либо обычное наследование, либо попытка притянуть за уши так называемый Duck Typing, где
просто создаются два идентичных по сути объекта, но с разным содержимым в print() и потом радостно заявляется, что можно
вызывать одинаковые методы если они есть.
Видимо, вся эта тема нужна тем, кто переходит на Python с других языков программирования, в которых какие-то другие концепции
при наследовании.
Полиморфизм означает, что разные объекты могут реагировать на один и тот же вызов функции или метода по-своему.
Простыми словами: два объекта могут иметь метод с одинаковым названием, который делает что-то разное но при это
можно спокойно использовать этот метод не заботясь о том какой-именно объект доступен.
class Dog: def speak(self): return "Woof!" class Cat: def speak(self): return "Meow!" def animal_sound(animal): print(animal.speak()) dog = Dog() cat = Cat() animal_sound(dog) # Woof! animal_sound(cat) # Meow!
И у собаки, и у кошки есть метод speak().
Метод animal_sound() не учитывает тип объекта.
Он просто вызывает animal.speak(), и каждый объект реагирует по-своему.
Пример
from abc import abstractmethod class Shape: @abstractmethod def area(self): pass class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return 3.1415 * self.radius ** 2 class Square(Shape): def __init__(self, side): self.side = side def area(self): return self.side ** 2 class Triangle(Shape): def __init__(self, base, height): self.base = base self.height = height def area(self): return self.base * self.height * 0.5 shapes = [Circle(4), Square(5), Triangle(6, 7)] for shape in shapes: print(shape.area())
python polymorphism_ex.py
50.264 25 21.0
Теперь создадим новый класс, который не наследует от Shape, не имеет своего метода area() и попробуем применить этот метод к нему.
# Создадим новый класс, не связанный с Shape class Pizza: def __init__(self, topping, radius): self.topping = topping self.radius = radius # Добавим пиццу в формы и посмотрим что будет с площадью shapes = [Circle(4), Square(5), Triangle(6, 7), Pizza("hawaii", 20)] for shape in shapes: print(shape.area())
50.264 25 21.0 Traceback (most recent call last): File "C:\Users\Andrei\polymorphism.py", line 45, in <module> print(shape.area()) AttributeError: 'Pizza' object has no attribute 'area'
Как и следовало ожидать - получили исключение
Если класс Pizza будет наследовать от Circle, у которого есть метод area() то ошибки не будет.
# Переделаем класс Pizza так, чтобы он наследовал от Circle class Pizza(Circle): def __init__(self, topping, radius): super().__init__(radius) self.topping = topping shapes = [Circle(4), Square(5), Triangle(6, 7), Pizza("hawaii", 20)] for shape in shapes: print(shape.area())
50.264 25 21.0 1256.6000000000001
Duck Typing
Лучшее объяснение, которое мне удалось найти заключается в том, что Python не делает явную проверку типа при работе с объектами.
class Duck: def quack(self): print('Quack, quack') def fly(self): print('Flap, Flap!') class Person: def quack(self): print("I'm Quacking Like a Duck!") def fly(self): print("I'm Flapping my Arms!") def quack_and_fly(thing): # Not Duck-Typed (Non-Pythonic) if isinstance(thing, Duck): thing.quack() thing.fly() else: print('This has to be a Duck!') d = Duck() quack_and_fly(d) p = Person() quack_and_fly(p)
Quack, quack Flap, Flap! This has to be a Duck!
В Python нормальным считается такой вариант
def quack_and_fly(thing): thing.quack() thing.fly() d = Duck() quack_and_fly(d) p = Person() quack_and_fly(p)
Quack, quack Flap, Flap! I'm Quacking Like a Duck! I'm Flapping my Arms!
Заметим что нигде нет явной проверки на наличие нужных методом. Если метода нет - будет исключение, это часть философии EAFP - Проще извиниться чем спросить разрешение которой придерживается Python.
Автор статьи: Андрей Олегович
| ООП в Python | |
| Классы | |
| Методы | |
| class variables | |
| class methods | |
| Статические методы | |
| Наследование | |
| super() | |
| Специальные методы | |
| dataclass | |
| __slots__ | |
| Декоратор property | |
| Полиморфизм |