Definition:
Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.
Explanation:
The Liskov Substitution Principle ensures that a subclass can stand in for its superclass without altering the desired properties of the program. This means that subclasses should override superclass methods without changing their expected behavior, maintaining consistency and reliability in the system’s functionality.
Example:
Consider a Bird class with a fly method. A Penguin subclass should not inherit from Bird if it cannot fly, as it would violate LSP.
# Violates LSP
class Bird:
def fly(self):
pass
class Sparrow(Bird):
def fly(self):
# Sparrow can fly
pass
class Penguin(Bird):
def fly(self):
raise NotImplementedError("Penguins can't fly")
# Adheres to LSP by refactoring
class Bird(ABC):
@abstractmethod
def move(self):
pass
class FlyingBird(Bird):
@abstractmethod
def fly(self):
pass
class Sparrow(FlyingBird):
def fly(self):
# Sparrow flies
pass
def move(self):
self.fly()
class Penguin(Bird):
def move(self):
# Penguins swim
pass