Kahibaro
Discord Login Register

Inheritance (basics)

What Is Inheritance?

Inheritance lets you create a new class based on an existing class.

The child class inherits attributes and methods from the parent class, and can:

This avoids writing the same code again and again when classes are similar.

In Python, you define a child class like this:

class Parent:
    pass
class Child(Parent):
    pass

Here, Child inherits from Parent.

A Simple Inheritance Example

Imagine a general Animal class and more specific animals like Dog and Cat.

class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        print("Some generic animal sound")
class Dog(Animal):
    pass
class Cat(Animal):
    pass
dog = Dog("Buddy")
cat = Cat("Misty")
dog.speak()  # Inherited from Animal
cat.speak()  # Inherited from Animal

Dog and Cat did not define __init__ or speak, but they can still use them because they inherit from Animal.

Adding New Behavior in the Child Class

A child class can have extra attributes or methods that the parent does not have.

class Animal:
    def __init__(self, name):
        self.name = name
    def info(self):
        print(f"I am an animal named {self.name}")
class Dog(Animal):
    def bark(self):
        print("Woof!")
dog = Dog("Rex")
dog.info()   # from Animal
dog.bark()   # only in Dog

The child class keeps everything from the parent and adds more.

Overriding Methods

Sometimes you want a child class to change how a method works.
This is called overriding a method.

class Animal:
    def speak(self):
        print("Some generic animal sound")
class Dog(Animal):
    def speak(self):
        print("Woof!")
class Cat(Animal):
    def speak(self):
        print("Meow!")
dog = Dog()
cat = Cat()
dog.speak()  # Woof!
cat.speak()  # Meow!

Here, Dog and Cat both override speak.
When you call speak on a Dog, you get the Dog version, not the Animal one.

Using `super()` to Reuse Parent Code

Sometimes you want to extend a parent method, not completely replace it.
You can call the parent’s version using super().

This is common with __init__.

class Animal:
    def __init__(self, name):
        self.name = name
class Dog(Animal):
    def __init__(self, name, breed):
        # Call Animal.__init__(self, name)
        super().__init__(name)
        self.breed = breed
dog = Dog("Rex", "Labrador")
print(dog.name)   # from Animal
print(dog.breed)  # from Dog

What happens:

  1. super().__init__(name) runs the parent’s __init__ to set self.name.
  2. Then the child class adds self.breed.

You can also use super() inside other methods:

class Animal:
    def info(self):
        print("I am an animal.")
class Dog(Animal):
    def info(self):
        super().info()        # Call parent version
        print("I am also a dog.")
dog = Dog()
dog.info()
# I am an animal.
# I am also a dog.

Inheritance vs. Just Using Attributes

You might wonder: why not just give every class the same attributes and methods manually?

Without inheritance:

class Dog:
    def __init__(self, name):
        self.name = name
    def speak(self):
        print("Woof!")
class Cat:
    def __init__(self, name):
        self.name = name
    def speak(self):
        print("Meow!")

Here, __init__ is duplicated. If you need to change how names are stored, you must change it in multiple places.

With inheritance:

class Animal:
    def __init__(self, name):
        self.name = name
class Dog(Animal):
    def speak(self):
        print("Woof!")
class Cat(Animal):
    def speak(self):
        print("Meow!")

Now, the shared part (__init__) lives in one place (Animal), and Dog and Cat only define what is different.

“Is-a” Relationship

A helpful rule: use inheritance when the relationship is “is-a”.

But if the relationship is more like “has-a”, you usually do not use inheritance.
For example:

Those are usually better handled with attributes (one object containing another), not inheritance.
(This idea—using objects inside other objects—is usually called composition, and can be explored separately.)

Basic Inheritance Example: Shapes

Here is a small example with a parent Shape and two child classes.

class Shape:
    def area(self):
        # Generic shape has no defined area
        return 0
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area(self):
        # Override parent method
        return self.width * self.height
class Square(Rectangle):
    def __init__(self, side):
        # A square is a rectangle with equal sides
        super().__init__(side, side)
rect = Rectangle(3, 4)
square = Square(5)
print(rect.area())    # 12
print(square.area())  # 25

What this shows:

When (and When Not) to Use Inheritance

Use inheritance when:

Be careful with inheritance when:

In those cases, it may be simpler to use normal attributes (objects containing other objects) instead of inheritance.

Small Practice Ideas

You can try building simple class trees like:

For each:

  1. Put shared attributes and methods in the parent class.
  2. Add specific behavior in each child class.
  3. Override at least one method in a child class.
  4. Optionally, use super() in a child __init__.

Views: 20

Comments

Please login to add a comment.

Don't have an account? Register now!