Inheritance And Polymorphism

Inheritance lets a child class reuse and extend the behavior of a parent class.

class SavingAccount(BankAccount):
    pass

The child has the parent functionality plus any extra functionality it defines.

Constructor Customization

A child class can call the parent constructor, then add its own attributes.

class SavingAccount(BankAccount):
    def __init__(self, balance, interest_rate):
        BankAccount.__init__(self, balance)
        self.interest_rate = interest_rate

In modern Python, super() is usually preferred when the inheritance hierarchy is more complex.

Method Overriding

A child class can override a parent method to customize behavior.

class Manager(Employee):
    def give_raise(self, amount, bonus=1.05):
        Employee.give_raise(self, amount * bonus)

Polymorphism

Polymorphism means using a common interface across different classes. Code can call the same method on different object types when those objects support the expected behavior.

Liskov Substitution Principle

The Liskov Substitution Principle says a base class should be replaceable by any subclass without breaking program behavior.

Violation examples:

  • subclass method requires extra parameters
  • subclass strengthens input conditions
  • subclass weakens output guarantees
  • subclass throws additional unexpected exceptions
  • subclass changes unrelated state

The square-rectangle problem is a classic violation. A square may seem like a rectangle mathematically, but if setting width and height independently is part of the rectangle interface, a square cannot safely substitute for a rectangle.

This connects to Dependency Injection because composition is often safer than inheritance when substitutability is unclear.