Что такое полиморфизм в ООП и как он реализуется в Python

Ответ

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

В Python полиморфизм проявляется несколькими способами:

1. Наследование и переопределение методов (Method Overriding)

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

class Shape:
    def area(self):
        raise NotImplementedError("Subclasses should implement this!")

class Square(Shape):
    def __init__(self, side):
        self.side = side

    def area(self):
        return self.side * self.side

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius * self.radius

# Единый интерфейс для разных объектов
for shape in [Square(5), Circle(3)]:
    print(f"Площадь фигуры: {shape.area()}")

2. "Утиная типизация" (Duck Typing)

Ключевая особенность Python. Поведение объекта определяется наличием у него необходимых методов, а не его типом или классом. "Если это выглядит как утка и крякает как утка, то это утка".

class Duck:
    def quack(self):
        print("Quack!")

class Person:
    def quack(self):
        print("I'm quacking like a duck!")

# Функция работает с любым объектом, у которого есть метод quack()
def make_it_quack(obj):
    obj.quack()

make_it_quack(Duck())
make_it_quack(Person())

Практический пример: Система обработки платежей

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

class PaymentGateway:
    def process_payment(self, amount):
        raise NotImplementedError

class StripeGateway(PaymentGateway):
    def process_payment(self, amount):
        print(f"Processing ${amount} payment via Stripe.")

class PayPalGateway(PaymentGateway):
    def process_payment(self, amount):
        print(f"Processing ${amount} payment via PayPal.")

# Основная логика не зависит от конкретной платежной системы
def execute_payment(gateway: PaymentGateway, amount: float):
    gateway.process_payment(amount)

stripe = StripeGateway()
paypal = PayPalGateway()

execute_payment(stripe, 100.0)
execute_payment(paypal, 50.0)

Ответ 18+ 🔞

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

Смотри, представь себе, что у тебя есть, допустим, команда «поехали». Ты её кричишь, и один чувак садится на велосипед, другой — в тачку, а третий, ёпта, на верблюда вскакивает. Все поехали, но каждый — по-своему, на своей хуйне. Вот это и есть полиморфизм, блядь! Одна команда, а реакция разная, в зависимости от того, кому и на чём ебашить.

В Питоне это вообще цветёт пиздопроебибна, потому что тут главное — не родословная, а умения. Есть у тебя метод quack() — значит, ты утка, и похуй, что ты на самом деле человек в костюме или радиоуправляемая игрушка.

Вот, смотри на примере, тут всё просто, как три копейки:

class УткаНастоящая:
    def крякать(self):
        print("Кря-кря, сука!")

class МужикПодвыпивший:
    def крякать(self):
        print("Я утка, блядь, кря-кря! Иди нахуй!")

# А эта функция — она вообще ни хуя не знает, кто перед ней.
# Ей главное, чтобы объект умел крякать.
def устроить_крякопаду(объект):
    объект.крякать()

# И вот она, магия, ёбана!
устроить_крякопаду(УткаНастоящая())
устроить_крякопаду(МужикПодвыпивший())

Видишь? Функции устроить_крякопаду похуй, что ей передали. Она тупо вызывает метод .крякать(). А уж как он там реализован — это проблемы того, кто его писал. Главное, чтобы он был. Это и есть «утиная типизация» в чистом виде, ядрёна вошь! Если крякает — значит, сойдёт за утку.

Ну а если по-взрослому, с наследованием, то это когда ты в родительском классе объявляешь какой-нибудь метод, а в детях его переписываешь под себя. Как будто отец сказал: «Сынок, иди заработай». Один пошёл код писать, другой — пирожки продавать, а третий — у олигарха крышу моет. Все заработали, но способы, блядь, овердохуищно разные.

class Отец:
    def заработать(self):
        raise NotImplementedError("Иди работай, паразит!")

class Программист(Отец):
    def заработать(self):
        print("Сижу, блядь, в конторе, пишу код. Получил сотку.")

class Спекулянт(Отец):
    def заработать(self):
        print("Купил доллары по 60, продал по 120. Молодец, какой.")

# А тут общий счётчик, которому похуй, как ты заработал.
def посчитать_доход(работник: Отец):
    работник.заработать()

посчитать_доход(Программист())
посчитать_доход(Спекулянт())

Вот и вся философия. Не нужно городить огород из проверок типов. Есть нужный метод — работаем. Нет — получишь ошибку, и сам виноват, пизда бородавчатая. Python так живёт, и, надо сказать, живёт неплохо. Главное — не выёбывайся и пиши методы так, чтобы их можно было вызывать одинаково. А там уже внутри твори, что хочешь.