Inheritance
Inheritance lets one class reuse and extend the behavior of another. The class being reused is called the parent (or base/superclass), and the class that reuses it is the child (or subclass). In Python you create this relationship by writing class Child(Parent): — the parentheses after the class name list which class it inherits from.
Basic inheritance and method overriding
A subclass automatically gets every method and attribute its parent defines. It can also override a method by defining a method with the same name — when that happens, Python uses the subclass's version instead of the parent's.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
animals = [Animal("Generic critter"), Dog("Rex"), Cat("Whiskers")]
for animal in animals:
print(animal.speak())Generic critter makes a sound Rex says Woof! Whiskers says Meow!
Both Dog and Cat inherit __init__ from Animal unchanged — they never redefine it, so Dog("Rex") runs Animal.__init__. They only override speak, which is exactly the point of overriding: keep what already works, replace only the behavior that needs to differ.
Extending the parent with super()
Sometimes a subclass needs to extend the parent's behavior rather than fully replace it — for example, adding extra setup on top of whatever the parent already does. Calling super().__init__(...) runs the parent's __init__ first, and then the subclass can add its own additional state.
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def describe(self):
return f"{self.name}: ${self.salary}/yr"
class Manager(Employee):
def __init__(self, name, salary, team=None):
super().__init__(name, salary) # run Employee's setup first
self.team = team if team is not None else []
def describe(self):
base = super().describe() # reuse the parent's formatting
return f"{base}, manages {len(self.team)} people"
alice = Employee("Alice", 65000)
bob = Manager("Bob", 95000, team=["Alice", "Carol"])
print(alice.describe())
print(bob.describe())Alice: $65000/yr Bob: $95000/yr, manages 2 people
Multiple levels of inheritance
Inheritance can chain across more than one level: a grandchild class can inherit from a child class, which itself inherits from a parent class. Each level can add or override behavior, and super() still walks up to the next class in that chain.
class Vehicle:
def __init__(self, brand):
self.brand = brand
def describe(self):
return f"A {self.brand} vehicle"
class Car(Vehicle):
def __init__(self, brand, doors):
super().__init__(brand)
self.doors = doors
def describe(self):
return f"{super().describe()} with {self.doors} doors"
class SportsCar(Car):
def __init__(self, brand, doors, top_speed):
super().__init__(brand, doors)
self.top_speed = top_speed
def describe(self):
return f"{super().describe()}, top speed {self.top_speed} km/h"
car = SportsCar("Ferrari", 2, 340)
print(car.describe())A Ferrari vehicle with 2 doors, top speed 340 km/h
Here SportsCar → Car → Vehicle is three levels deep, and each describe override builds on the previous level's result via super() rather than rewriting it from scratch.
Checking relationships: isinstance() and issubclass()
isinstance(obj, SomeClass) checks whether obj is an instance of SomeClass or any of its subclasses. issubclass(ClassA, ClassB) checks the class relationship directly, asking whether ClassA inherits from ClassB (or is ClassB itself).
rex = Dog("Rex")
print(isinstance(rex, Dog)) # rex is directly a Dog
print(isinstance(rex, Animal)) # Dog is a subclass of Animal, so True
print(isinstance(rex, Cat)) # Dog is unrelated to Cat
print(issubclass(Dog, Animal)) # Dog inherits from Animal
print(issubclass(Animal, Dog)) # the reverse is not true
print(issubclass(SportsCar, Vehicle)) # true across two levelsTrue True False True False True
class Child(Parent):creates the inheritance relationship.Overriding a method means defining one with the same name in the subclass — the subclass version wins.
super().method(...)calls the parent's version, useful for extending rather than fully replacing behavior.isinstance()checks object-to-class membership (including subclasses);issubclass()checks class-to-class inheritance.