Concepts / Inheritance

Inheritance

One major real benefit of inheritance is code reuse: a common base class can hold shared behavior, and specific classes can inherit from it and add only what makes them different.

  • CORE CONCEPT
  • Programming
Interactive lab

Try it: Inheritance and Method Lookup

How a subclass inherits from its parent, how Python finds an attribute by walking the instance, then the class's method resolution order up to object, how overriding and super() work, why the same call does different things on different objects (polymorphism), and what isinstance / issubclass check.

How it works

  1. class Dog(Animal) gives Dog the MRO Dog → Animal → object; Puppy(Dog) gives Puppy → Dog → Animal → object.
  2. obj.name searches obj.__dict__, then each class of type(obj).__mro__ in order; the first class that defines the name wins, so a subclass method overrides the parent's.
  3. super().method() starts the search in the class after the one the current method was defined in, e.g. to run the parent's __init__.
  4. Calling the same method on a list of different objects runs each object's own version (polymorphism).
  5. isinstance(obj, C) is True when C is in type(obj).__mro__; if no class has the name, Python raises AttributeError.

Default run (63 steps): Ready: Animal, Dog, Cat and Puppy, then the statements you picked. Each attribute is searched along the class's MRO. … Finished. Printed: Rex the dog says Woof / Tom the cat says Meow / Bo the dog says Woof! / True / Puppy / Dog / Animal / object.

Simplified: The lab's own small Python interpreter runs a fixed, hand-written script (you choose the variant and the values, never the code); nothing is executed as real Python. Every script was run in CPython 3.12 with the same inputs and the lab reproduces its output and error messages. Single inheritance only (the lab's MRO code is Python's C3 algorithm, but no class here has two parents).

Educational simulation

Loading the simulation…

Why Inheritance Matters

Imagine you are building a school management system. You need to represent both teachers and students. Both have names, ages, and addresses. Both can introduce themselves. Without inheritance, you would write the name, age, and address attributes twice—once in a Teacher class and once in a Student class. You would also duplicate the introduction logic. This duplication makes your code harder to maintain: if you discover a bug in how addresses are stored, you have to fix it in two places. Inheritance solves this problem by letting you define shared behavior once in a base class, then have Teacher and Student inherit that shared behavior while adding only what makes each one unique.

Key point

One major real benefit of inheritance is code reuse: a common base class can hold shared behavior, and specific classes can inherit from it and add only what makes them different.

The Type and Subtype Relationship

Inheritance creates a type/subtype relationship. When you say 'Teacher inherits from SchoolMember,' you are declaring that Teacher is a specialized kind of SchoolMember. Every Teacher is a SchoolMember, but not every SchoolMember is a Teacher. This relationship is fundamental to how inheritance works: the subclass (Teacher) becomes a more specific version of the base class (SchoolMember). The subclass automatically receives all the attributes and methods of the base class, then can add its own specialized attributes and methods on top.

SchoolMemberBase Class: name, age,address, introduce()TeacherInherits: name, age,address, introduce() |Adds: subject, salary,grade_assignment()StudentInherits: name, age,address, introduce() |Adds: student_id,grade_level,submit_homework()inherits frominherits from
How does a subclass relate to its parent class? What does it inherit and what can it add? Teacher and Student both inherit from SchoolMember, receiving shared attributes like name and age, while each adds specialized attributes and methods.
In the real world

Think of inheritance like a biological classification. All dogs are animals. All animals are living things. A dog inherits the property of being alive from the animal class, but a dog also has specialized behaviors like barking that other animals might not have. In code, a Dog class would inherit from an Animal class, receiving attributes like heartbeat and age, while adding dog-specific methods like bark().

Python Inheritance Syntax

To use inheritance in Python, the base class name is listed in a tuple following the new class's own name in its definition. The syntax is: class ChildClass(ParentClass):. The parentheses after the child class name contain the parent class (or classes, if using multiple inheritance). When you define a child class this way, it automatically inherits all attributes and methods from the parent class.

python
Notes on the code
  • SchoolMember is the base class with shared attributes and methods
  • Teacher inherits from SchoolMember using the syntax class Teacher(SchoolMember):
  • super().__init__() calls the parent class's __init__ to initialize shared attributes
  • Teacher adds its own specialized attributes: subject and salary
  • Student also inherits from SchoolMember and adds its own specialized attributes

How Inheritance Flows in Action

When you create an instance of Teacher or Student, the inheritance relationship means both the parent class's initialization and the child class's initialization run. The child class receives all the parent's attributes and methods automatically, so a Teacher instance has name, age, address, and introduce() even though those are defined in SchoolMember. The child class can then add specialized attributes and methods that only it has.

Worked example

Creating and Using Inherited Classes

Create a Teacher instance named Alice, age 35, living at 123 Oak Street, teaching Math with a salary of 50000. Then create a Student instance named Bob, age 14, living at 456 Elm Street, with student ID 1001 and grade level 9. Call introduce() on both to see the inherited behavior in action.

  1. 1
    Create the Teacher instance

    teacher = Teacher('Alice', 35, '123 Oak Street', 'Math', 50000). The Teacher.__init__ calls super().__init__() to initialize name, age, and address from SchoolMember, then sets subject and salary.

  2. 2
    Create the Student instance

    student = Student('Bob', 14, '456 Elm Street', 1001, 9). The Student.__init__ calls super().__init__() to initialize name, age, and address from SchoolMember, then sets student_id and grade_level.

  3. 3
    Call introduce() on the Teacher

    teacher.introduce() returns 'I am Alice, age 35, living at 123 Oak Street'. This method is inherited from SchoolMember and works on the Teacher instance because Teacher is a subtype of SchoolMember.

  4. 4
    Call introduce() on the Student

    student.introduce() returns 'I am Bob, age 14, living at 456 Elm Street'. The same inherited method works on Student because Student is also a subtype of SchoolMember.

  5. 5
    Call specialized methods

    teacher.grade_assignment('Bob', 'A') returns 'Graded Bob's assignment: A'. student.submit_homework('Math Project') returns 'Submitted: Math Project'. These methods are unique to each subclass.

Result

Both Teacher and Student instances have the shared introduce() method from SchoolMember, but each also has its own specialized methods. Code is not duplicated; the shared behavior lives in one place.

python
Output (expected)
I am Alice, age 35, living at 123 Oak Street
I am Bob, age 14, living at 456 Elm Street
Graded Bob's assignment: A
Submitted: Math Project

Multiple Inheritance

When more than one class is listed in that inheritance tuple, this is specifically called multiple inheritance. For example, you could write class TeachingAssistant(Teacher, Student): to create a class that inherits from both Teacher and Student. Python will look for methods and attributes in the order the parent classes are listed. Multiple inheritance is powerful but can become complex, so it is used less frequently than single inheritance in practice.

python

Common Mistakes with Inheritance

  • Common mistake

    Forgetting to call super().__init__() in the child class's __init__ method

    What it looks like
    class Teacher(SchoolMember):
        def __init__(self, name, age, address, subject):
            self.subject = subject  # Missing super().__init__(...)
    Why it fails

    The parent class's __init__ is not called, so name, age, and address are never initialized. Any code that tries to access teacher.name will fail.

    Do this instead

    Always call super().__init__() with the appropriate arguments before setting child-specific attributes: super().__init__(name, age, address)

  • Common mistake

    Assuming a child class instance is an instance of the parent class

    What it looks like
    teacher = Teacher('Alice', 35, '123 Oak Street', 'Math', 50000)
    if isinstance(teacher, SchoolMember):
        print('This is True!')
    Why it fails

    Actually, this is correct—a child class instance IS an instance of the parent class. The mistake is the opposite: assuming a parent class instance is an instance of the child class, which is false.

    Do this instead

    Remember: every Teacher is a SchoolMember, but not every SchoolMember is a Teacher. Use isinstance() correctly to check the actual type.

  • Common mistake

    Creating a deep inheritance hierarchy when composition would be simpler

    What it looks like
    class Animal: pass
    class Mammal(Animal): pass
    class Carnivore(Mammal): pass
    class Dog(Carnivore): pass
    Why it fails

    Deep hierarchies are hard to understand and maintain. If you only need Dog to have certain behaviors, you do not need four levels of inheritance.

    Do this instead

    Keep inheritance hierarchies shallow and focused. Use composition (having an object contain another object) when the relationship is not a true type/subtype relationship.

  • Common mistake

    Overriding a parent method without understanding the parent's behavior

    What it looks like
    class SchoolMember:
        def introduce(self):
            return f'I am {self.name}'
    
    class Teacher(SchoolMember):
        def introduce(self):
            return f'Teacher: {self.name}'  # Loses the age and address info
    Why it fails

    The child's override replaces the parent's method entirely. If the parent's method has important logic, you lose it.

    Do this instead

    If you need to extend a parent method, call super().method_name() to preserve the parent's behavior, then add your own: return super().introduce() + f', teaching {self.subject}'

When to Use Inheritance

Use inheritance when you have a genuine type/subtype relationship. Ask yourself: Is the child class a specialized version of the parent class? Can you say 'every instance of the child class is also an instance of the parent class'? If yes, inheritance is appropriate. If you are just trying to reuse some code but the relationship is not a true type/subtype, consider composition instead—having one class contain an instance of another class.

Practice: Building Your Own Inheritance Hierarchy

MEDIUM

Design a simple inheritance hierarchy for a pet store system. Create a base class Pet with attributes name, age, and a method speak(). Then create at least two subclasses—Dog and Cat—that inherit from Pet. Each subclass should override the speak() method to return a dog-specific or cat-specific sound. Create instances of both subclasses and call speak() on each to verify the inheritance and method override work correctly.

Hints
  • Start by defining the Pet base class with __init__ and speak() methods
  • Use class Dog(Pet): to create the Dog subclass
  • Call super().__init__() in each subclass's __init__ to initialize the parent attributes
  • Override speak() in each subclass to return a different sound
  • Create instances and test that each subclass's speak() method returns the correct sound

Summary

Inheritance is a core feature of object-oriented programming that lets you create a type/subtype relationship between classes. A subclass inherits all attributes and methods from its parent class, then adds or overrides them to create specialized behavior. The Python syntax is simple: class Child(Parent):. The main benefit is code reuse—shared behavior lives in the parent class once, and multiple child classes can inherit it without duplication. Use inheritance for genuine 'is-a' relationships, keep hierarchies shallow, always call super().__init__() in child constructors, and remember that every instance of a child class is also an instance of the parent class.

At a glance

  • Inheritance creates a type/subtype relationship, allowing a child class to reuse behavior from a parent class while adding specialization.
  • The Python syntax class Child(Parent): declares that Child inherits from Parent and automatically receives all of Parent's attributes and methods.
  • Use super().__init__() in a child class's __init__ to initialize parent attributes before setting child-specific attributes.
  • Inheritance solves code duplication by centralizing shared behavior in a base class that multiple specialized classes can inherit from.
  • Use inheritance for genuine 'is-a' relationships; if the relationship is 'has-a', composition is often a better design choice.

Related concepts

More concepts starting with I