Ответ
Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP) — это один из пяти принципов SOLID. Он гласит, что объекты производного (дочернего) класса должны быть способны заменять объекты базового (родительского) класса без изменения корректности работы программы.
Простыми словами: если у вас есть функция, которая работает с классом A
, она должна так же корректно работать с любым его подклассом B
, не зная о существовании B
.
Почему это важно? LSP гарантирует, что иерархия наследования является семантически правильной. Подкласс должен расширять, а не изменять поведение базового класса.
Классический пример нарушения LSP (проблема квадрата и прямоугольника):
class Rectangle:
def __init__(self, width, height):
self._width = width
self._height = height
def set_width(self, width):
self._width = width
def set_height(self, height):
self._height = height
def get_area(self):
return self._width * self._height
# Квадрат — это частный случай прямоугольника, но...
class Square(Rectangle):
def __init__(self, side):
super().__init__(side, side)
# Нарушение: изменение ширины влияет на высоту, что неверно для базового класса
def set_width(self, width):
self._width = width
self._height = width
# Аналогичное нарушение
def set_height(self, height):
self._width = height
self._height = height
# Функция, которая ожидает поведение Rectangle
def process_rectangle(rect: Rectangle):
rect.set_width(5)
rect.set_height(10)
# Ожидаем площадь 5 * 10 = 50
print(f"Ожидаемая площадь: 50, Фактическая: {rect.get_area()}")
# С базовым классом всё работает
process_rectangle(Rectangle(2, 3)) # Фактическая: 50
# С подклассом поведение нарушается
process_rectangle(Square(2)) # Фактическая: 100 (т.к. set_height изменила и ширину)
Этот код нарушает LSP, потому что Square
изменяет инвариант (независимость ширины и высоты), установленный в Rectangle
. Это приводит к непредсказуемым результатам.