В чем разница между композицией и наследованием в Python

Ответ

Наследование и композиция — это два основных механизма для построения отношений между классами в ООП.

Наследование (отношение "является" / is-a)

Наследование создает иерархию, где дочерний класс (подкласс) получает все атрибуты и методы родительского класса (суперкласса). Это жесткая связь.

Пример: Dog является Animal.

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        raise NotImplementedError("Subclass must implement abstract method")

class Dog(Animal): # Dog наследует от Animal
    def speak(self):
        return f"{self.name} says Woof!"

Композиция (отношение "имеет" / has-a)

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

Пример: Car имеет Engine.

class Engine:
    def start(self):
        return "Engine started"

class Car:
    def __init__(self):
        self.engine = Engine() # Car содержит экземпляр Engine

    def start(self):
        print("Starting the car...")
        return self.engine.start()

Сравнение

Критерий Наследование Композиция
Тип связи is-a (жесткая связь) has-a (гибкая связь)
Гибкость Низкая. Изменения в базовом классе влияют на всех потомков. Высокая. Внутренние объекты можно легко заменять.
Переиспользование Переиспользуется реализация родителя. Переиспользуется интерфейс вложенного объекта.

Основной принцип: "Предпочитайте композицию наследованию" (Composition over inheritance). Композиция ведет к созданию более гибких, слабосвязанных и легко тестируемых систем.

Ответ 18+ 🔞

Да ты посмотри, какая тема подъехала! Наследование и композиция, блядь. Это ж как два пути в тёмном лесу: один — протоптанная, но скользкая тропа предков, а второй — своя, кривая, но своя дорожка.

Наследование — это когда ты «являешься» (is-a). Жёсткая, блядь, связь, как родня невыносимая. Всё, что было у родителя, теперь и твоё, хочешь ты того или нет.

Пример: Собака является Животным. Ну, логично же, ёпта.

class Животное:
    def __init__(self, имя):
        self.имя = имя

    def говори(self):
        raise NotImplementedError("Потомок, иди сюда, сделай сам, нахуй!")

class Собака(Животное): # Собака наследует от Животного. Всё, приехали.
    def говори(self):
        return f"{self.имя} гавкает: Гав!"

Взял всё, что было у Животного, и теперь ещё и гавкать обязан. Судьба, блядь.

А теперь композиция — это когда ты «имеешь» (has-a). Гибко, модно, молодёжно. Не «я — это ты», а «у меня внутри есть такая штука». Как двигатель в машине.

Пример: Машина имеет Двигатель. Не является же она двигателем, в рот меня чих-пых!

class Двигатель:
    def заведись(self):
        return "Двигатель: Вррр-р-р!"

class Машина:
    def __init__(self):
        self.двигатель = Двигатель() # Машина СОДЕРЖИТ в себе Двигатель. Не родила, а купила!

    def поехали(self):
        print("Поворачиваю ключ...")
        return self.двигатель.заведись()

Вот это подход! Захотел — поставил турбированный движок, захотел — электромотор. Гибкость — овердохуища!

Так в чём же, сука, разница?

Критерий Наследование Композиция
Связь is-a (Я — твой сын, папаша, всё наше — моё). Жёсткая. has-a (У меня в кармане есть эта фигня). Гибкая.
Гибкость Низкая, блядь. Чихнул родитель — все потомки заболели. Высокая! Внутреннюю детальку — выкинул, другую вставил.
Переиспользование Тащишь за собой весь скарб родительского класса, даже его старый диван. Переиспользуешь только интерфейс, только договорённость, как эта штука должна работать.

Главный вывод, который все зубрят, но многие игнорят: «Предпочитай композицию наследованию». Это не просто так, это чтобы твой код не превратился в хлипкое, блядь, фамильное древо, где все держатся друг за друга и падают от одного чиха. Композиция делает систему слабосвязанной, как хороший конструктор. Собрал, разобрал, ебушки-воробушки, и всё работает.