Полиморфизм: переопределение методов и работа с разными типами

Полиморфизм — это магия Python! ✨

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

print(len("Привет"))    # 6 (символов)
print(len([1, 2, 3]))   # 3 (элемента)

Одна функция len(), но разное поведение для разных типов данных. 🔄


Переопределение методов: когда наследники умнее родителей 🧬

В ООП полиморфизм часто проявляется через переопределение методов — дочерние классы могут менять поведение методов, унаследованных от родителя.

class Animal:
    def make_sound(self):
        print("Какой-то звук")

class Cat(Animal):
    def make_sound(self):  # Переопределили метод!
        print("Мяу!")

class Dog(Animal):
    def make_sound(self):  # И здесь тоже!
        print("Гав!")

animals = [Cat(), Dog()]
for animal in animals:
    animal.make_sound()  # Один вызов — разное поведение

Вывод:

Мяу!
Гав!

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


Duck Typing: если ходит как утка... 🦆

В Python важна не столько принадлежность к классу, сколько наличие нужных методов. Это называют "утиной типизацией":

class Car:
    def move(self):
        print("Еду на колёсах")

class Boat:
    def move(self):
        print("Плыву по волнам")

def travel(vehicle):
    vehicle.move()  # Нам важно только наличие метода move()

travel(Car())   # Еду на колёсах
travel(Boat())  # Плыву по волнам

Объекты могут быть любого типа — главное, чтобы поддерживали ожидаемое поведение. Данила Бежин на своём YouTube-канале называет это "договором между объектами". 🤝


Магические методы и полиморфизм 🔮

Перегрузка операторов через магические методы — классический пример полиморфизма:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):  # Переопределяем сложение
        return Vector(self.x + other.x, self.y + other.y)

    def __str__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)  # Vector(4, 6)

Теперь оператор + работает с нашими векторами! Аналогично можно переопределять *, == и другие операторы.


Практический пример: универсальный обработчик данных 🛠️

Допустим, мы пишем функцию для сохранения данных в разных форматах:

class JSONSerializer:
    def serialize(self, data):
        import json
        return json.dumps(data)

class XMLSerializer:
    def serialize(self, data):
        return f"<data>{data}</data>"  # Упрощённый пример

def save_data(serializer, data):
    print(f"Сохранение: {serializer.serialize(data)}")

save_data(JSONSerializer(), {"key": "value"})
save_data(XMLSerializer(), "some_data")

Вывод:

Сохранение: {"key": "value"}
Сохранение: <data>some_data</data>

Функция save_data работает с любым объектом, у которого есть метод serialize() — полиморфизм в чистом виде! 💎


Когда полиморфизм особенно полезен 🌟

1. Работа с коллекциями разных типов:

def total_length(items):
    return sum(len(item) for item in items)

print(total_length(["abc", [1, 2], (9, 8, 7)]))  # 6

2. Плагины и расширения — когда нужно поддерживать разные реализации.

3. API-интерфейсы — один метод, разное поведение для разных входных данных.


Вместо заключения: полиморфизм вокруг нас 🌍

Каждый раз, когда ты используешь + и для чисел, и для строк, или видишь, как print() корректно выводит любой объект — это полиморфизм. Он делает код: - Гибким 🤸 - Расширяемым 🏗️ - Интуитивно понятным 🧠

Попробуй применить эти принципы в своём следующем проекте!

Скрыть рекламу навсегда

📘 VK Видео — обучение без ограничений

Все уроки доступны без VPN, без блокировок и зависаний.

Можно смотреть с телефона, планшета или компьютера — в любое время.

▶️ Смотреть на VK Видео