Как Принцип подстановки Барбары Лисков (LSP) связан с полиморфизмом в ООП

«Как Принцип подстановки Барбары Лисков (LSP) связан с полиморфизмом в ООП» — вопрос из категории ООП, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Принцип подстановки Барбары Лисков (LSP) является фундаментальным правилом для корректной реализации полиморфизма подтипов. Он утверждает, что объекты производных классов должны быть взаимозаменяемы с объектами базового класса без изменения ожидаемого поведения программы.

Проще говоря, если LSP соблюдается, полиморфный код, работающий с базовым классом, будет корректно работать и с любым его подклассом. Нарушение LSP ведет к необходимости проверок типа (isinstance) и условной логике, что ломает идею полиморфизма.

Пример нарушения LSP

Рассмотрим классический пример с птицами. Если базовый класс Bird имеет метод fly(), то подкласс Penguin нарушит LSP, так как пингвины не летают.

class Bird:
    def fly(self):
        print("Эта птица летит")

class Duck(Bird):
    # Утка - птица, она летает. LSP не нарушен.
    def fly(self):
        print("Утка летит, крякая")

class Penguin(Bird):
    # Пингвин - птица, но он не летает. Нарушение LSP.
    def fly(self):
        raise NotImplementedError("Пингвины не могут летать!")

# Полиморфная функция
def make_bird_fly(bird: Bird):
    try:
        bird.fly()
    except NotImplementedError as e:
        print(f"Ошибка: {e}")

# Использование
duck = Duck()
penguin = Penguin()

make_bird_fly(duck)     # Вывод: Утка летит, крякая
make_bird_fly(penguin)  # Вывод: Ошибка: Пингвины не могут летать!

Код, ожидающий объект типа Bird, ломается при передаче Penguin. Это прямое следствие нарушения LSP. Правильным решением было бы создание более гранулярной иерархии, например, Bird -> FlyingBird.