← Назад к вопросам

Всегда ли наследование полиморфно

1.7 Middle🔥 191 комментариев
#Python Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Наследование и полиморфизм в Python

Нет, наследование не всегда полиморфно. Это два разных концепта, хотя они часто работают вместе.

Разница между наследованием и полиморфизмом

Наследование — это механизм, при котором дочерний класс получает атрибуты и методы от родительского класса. Это про переиспользование кода.

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

Наследование без полиморфизма

Можно наследовать класс, но не переопределять методы (не переживать полиморфизм):

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} издаёт звук")

class Dog(Animal):
    pass  # Просто наследуем, не переопределяем

dog = Dog("Rex")
dog.speak()  # Rex издаёт звук

Здесь Dog наследует speak() от Animal, но не переопределяет его. Полиморфизма нет — просто переиспользование кода.

Полиморфизм через наследование

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

class Animal:
    def speak(self):
        pass  # Абстрактный метод

class Dog(Animal):
    def speak(self):
        return "Гав!"

class Cat(Animal):
    def speak(self):
        return "Мяу!"

class Bird(Animal):
    def speak(self):
        return "Чирик!"

def make_animal_speak(animal: Animal):
    print(animal.speak())  # Вызов работает для любого Animal

for animal in [Dog(), Cat(), Bird()]:
    make_animal_speak(animal)  # Каждый животное отвечает по-своему

Здесь полиморфизм позволяет вызывать speak() на объекте типа Animal, не зная точный класс.

Полиморфизм БЕЗ наследования (утиная типизация)

Python поддерживает полиморфизм без наследования — через «утиную типизацию» (duck typing):

class Guitar:
    def play(self):
        return "Дзинь-дзинь!"

class Piano:
    def play(self):
        return "Динь-динь!"

class Violin:
    def play(self):
        return "Писк!"

def perform(instrument):
    print(instrument.play())  # Не проверяем тип, просто вызываем play()

for instrument in [Guitar(), Piano(), Violin()]:
    perform(instrument)  # Работает для любого объекта с методом play()

Здесь нет наследования, но есть полиморфизм! Главное — объект имеет нужный метод.

Абстрактные базовые классы (ABC)

Для явного определения контракта используй абстрактные классы:

from abc import ABC, abstractmethod

class Transport(ABC):
    @abstractmethod
    def move(self):
        pass

class Car(Transport):
    def move(self):
        return "Машина едет"

class Plane(Transport):
    def move(self):
        return "Самолёт летит"

# Transport() — ошибка, ABC не может быть instantiated
# Car() и Plane() — работают, реализовали move()

Выводы

  1. Наследование ≠ полиморфизм. Наследование — способ повторно использовать код
  2. Полиморфизм нужно реализовывать через переопределение методов
  3. Python допускает полиморфизм без наследования (duck typing)
  4. Используй ABC, если хочешь явный контракт и безопасность типов