Полиморфизм и «утиная типизация»
Полиморфизм — это когда разные объекты отвечают на один и тот же вызов по‑разному. Важно не «к какому типу он принадлежит», а «умеет ли он делать нужное действие». В Python это особенно естественно благодаря «утиной типизации»: если объект «крякает как утка» (имеет нужные методы), его можно передать туда, где ожидается «утка» — даже без наследования.
Единый интерфейс — разное поведение
class HockeyPlayer:
def __init__(self, name, team):
self.name = name
self.team = team
def role(self):
return 'Игрок'
class Goalkeeper(HockeyPlayer):
def role(self):
return 'Вратарь'
def announce(entity):
# ожидаем, что есть метод role()
print(entity.role())
players = [HockeyPlayer('Иван', 'Метеор'), Goalkeeper('Павел', 'Вымпел')]
for p in players:
announce(p)
Игрок
Вратарь
«Утиная типизация»: наследование не обязательно
Если объект реализует нужные методы, он подходит — даже если не наследуется от «нашего» класса.
class Referee:
def __init__(self, name):
self.name = name
def role(self):
return 'Судья'
def announce(entity):
# entity не обязан быть наследником HockeyPlayer — лишь бы у него был role()
print(entity.role())
announce(Referee('Олег'))
Судья
Полиморфная функция: работаем через общий контракт
Пишем функцию, которая формирует «бейджик» для любого объекта с полями .name и методом .role().
def make_badge(entity):
return f"{entity.role()}: {entity.name}"
class Fan:
def __init__(self, name):
self.name = name
def role(self):
return 'Фанат'
print(make_badge(HockeyPlayer('Иван', 'Метеор')))
print(make_badge(Goalkeeper('Павел', 'Вымпел')))
print(make_badge(Fan('Саша')))
Игрок: Иван
Вратарь: Павел
Фанат: Саша
Мини‑памятка
- Сосредотачивайтесь на поведении (наличии методов), а не на иерархии типов.
- Полиморфизм упрощает код: один алгоритм — разные реализации.
- Утиная типизация позволяет писать функции, которые принимают «всё, что ведёт себя как…». Это гибко, но требует ясного контракта (какие методы вы ожидаете).