Inheritance
Inheritance is a way for one class to reuse another class's behavior by becoming a sub-type of it -- implementing a type/subtype relationship.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 ProjectMultiple 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.
Common Mistakes with Inheritance
Forgetting to call super().__init__() in the child class's __init__ method
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.
Fix:
Always call super().__init__() with the appropriate arguments before setting child-specific attributes: super().__init__(name, age, address)Assuming a child class instance is an instance of the parent class
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.
Fix:
Remember: every Teacher is a SchoolMember, but not every SchoolMember is a Teacher. Use isinstance() correctly to check the actual type.Creating a deep inheritance hierarchy when composition would be simpler
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.
Fix:
Keep inheritance hierarchies shallow and focused. Use composition (having an object contain another object) when the relationship is not a true type/subtype relationship.Overriding a parent method without understanding the parent's behavior
The child's override replaces the parent's method entirely. If the parent's method has important logic, you lose it.
Fix:
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
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.
Key Takeaways
- 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.