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.
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
- class Dog(Animal) gives Dog the MRO Dog → Animal → object; Puppy(Dog) gives Puppy → Dog → Animal → object.
- 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.
- 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__.
- Calling the same method on a list of different objects runs each object's own version (polymorphism).
- 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).
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.
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.
- 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.
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.
- 1Create the Teacher instance
teacher =
Teacher('Alice', 35, '123 Oak Street', 'Math', 50000). The Teacher.__init__callssuper().__init__() to initialize name, age, and address from SchoolMember, then sets subject and salary. - 2Create the Student instance
student =
Student('Bob', 14, '456 Elm Street', 1001, 9). The Student.__init__callssuper().__init__() to initialize name, age, and address from SchoolMember, then setsstudent_idandgrade_level. - 3Call 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. - 4Call 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. - 5Call 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
Common mistake Forgetting to call super().__init__() in the child class's __init__ method
What it looks likeclass Teacher(SchoolMember): def __init__(self, name, age, address, subject): self.subject = subject # Missing super().__init__(...)Why it failsThe parent class's
__init__is not called, so name, age, and address are never initialized. Any code that tries to accessteacher.namewill fail.Do this insteadAlways 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 liketeacher = Teacher('Alice', 35, '123 Oak Street', 'Math', 50000) if isinstance(teacher, SchoolMember): print('This is True!')Why it failsActually, 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 insteadRemember: 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 likeclass Animal: pass class Mammal(Animal): pass class Carnivore(Mammal): pass class Dog(Carnivore): passWhy it failsDeep 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 insteadKeep 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 likeclass 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 infoWhy it failsThe child's override replaces the parent's method entirely. If the parent's method has important logic, you lose it.
Do this insteadIf 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__andspeak()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.