Skip to main content

Inheritance and Method Resolution Order

In Chapter 29, you built the foundations of object-oriented programming: classes that encapsulate data and behavior, methods that transform state, and principles of good design. Now we're stepping into the professional OOP world where you design systems with multiple related classes that share behavior and specialize behavior through inheritance.

Inheritance is the mechanism that lets you create hierarchies of classes, from general to specific. A Dog is-a Animal, an ElectricCar is-a Car. This "is-a" relationship is powerful: it lets you reuse code, create flexible designs, and build systems where many different types work through a common interface. But inheritance is also subtle. Get it wrong, and you'll spend hours debugging which method actually got called.

In this lesson, you'll master the technical skill of inheritance and the conceptual skill of Method Resolution Order (MRO): the mechanism that answers the question "When I call dog.speak(), which speak() method does Python actually execute?" Understanding MRO is the difference between writing confident inheritance code and staring at confusing behavior in multi-level hierarchies.


Single Inheritance: The Parent-Child Relationship

Let's start simple. The most common pattern is single inheritance: a child class has one parent.

Inheritance hierarchy diagram showing parent-child relationships in Python classes, demonstrating single and multiple inheritance patterns with method override and super() call flow

Loading Python environment...

Notice the syntax: class Dog(Animal): means "Dog is a child of Animal" and super().__init__(name) calls the parent's __init__ method.

💬 AI Colearning Prompt

"Explain exactly what happens when we call super().__init__(name) in the Dog constructor. What if we forgot to call it? Show me the difference in memory state."


The super() Function: Calling Parent Methods

The super() function is a gateway to parent class methods. It's more sophisticated than you might think.

Loading Python environment...

The key insight: super() respects the parent's initialization, ensuring both parent and child set up their state correctly. This is critical for avoiding bugs.

🎓 Expert Insight

In AI-native development, inheritance hierarchies model agent types and capabilities. Understanding super() prevents subtle bugs where initialization gets skipped. In multi-agent systems, a misconfigured agent might seem to have a capability it doesn't actually have because its parent's initialization was skipped.

🚀 CoLearning Challenge

Ask your AI Co-Teacher: "I have a Person class with age. I create a Manager subclass that adds salary. Write the init methods correctly using super(). Then explain what happens if I forget the super() call."


Method Overriding: Specialization

When a child class provides its own version of a parent method, that's method overriding. The child's version replaces the parent's version:

Loading Python environment...

This code works because Python uses polymorphism: the same method name (area()) works differently on different object types. Python looks at the actual object type and calls the appropriate version. A Circle's area() calculates circles differently from a Rectangle's area(), but the caller doesn't need to know which type they have.


Multiple Inheritance: Two Parents

Python allows a class to inherit from multiple parents:

Loading Python environment...

A Duck inherits both flying and swimming abilities. This is powerful but introduces complexity: what happens when two parents have methods with the same name?


The Diamond Problem: Multiple Paths to the Same Parent

Here's where MRO becomes critical. Imagine this inheritance structure:

       A (has greet() method)
/ \
B C (both override greet())
\ /
D

This is called the diamond problem because of its shape. When D inherits from both B and C, and both inherit from A, we have two inheritance paths to A:

  • Path 1: D → B → A
  • Path 2: D → C → A

If we call d.greet(), which version gets called? B's or C's? And does A's greet() get called?

Loading Python environment...

Run this code and you'll see:

Hello from B
[<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]

The MRO tells us: Check D, then B, then C, then A, then object. That's the order Python searches for methods. Since B is listed first (left parent in class D(B, C)), B's greet() is found and executed.

💬 AI Colearning Prompt

"Explain why Python searches D → B → C → A in that order instead of D → B → A → C. What principle ensures this order makes sense?"


Method Resolution Order (MRO): The Deep Dive

MRO is the ordered list of classes Python searches to find a method. Python uses an algorithm called C3 Linearization to compute MRO. Here's the principle:

  1. Subclasses before parents — Always check D before B before A
  2. Inheritance order preserved — If a class inherits from (B, C), search B before C
  3. No class visited twice — Once A is in the search order, it appears exactly once, at the deepest level

🎓 Expert Insight

C3 Linearization prevents the chaos of older languages where the diamond problem could cause the same parent method to be called twice. Python solved this elegantly: every class appears exactly once, in a consistent order. This matters profoundly in AI agent hierarchies where you might have BaseAgent → SpecializedAgent → (ChatMixin, ToolMixin) → SomeAgent. Without C3, you'd have ambiguous behavior.

Here's a more complex example to see MRO in action:

Loading Python environment...

Output:

Car ignition sequence
[<class 'AmphibiousCar'>, <class 'Car'>, <class 'Boat'>, <class 'Vehicle'>, <class 'object'>]

The MRO is: AmphibiousCar → Car → Boat → Vehicle → object. Since Car comes before Boat (the inheritance order in class AmphibiousCar(Car, Boat)), Car's start() is found first and called.

🚀 CoLearning Challenge

Create a diamond inheritance example (Device, Phone adds call(), Computer adds compute(), Smartphone inherits from both). Add a start() method in Device and override it in Phone and Computer. Call start() from a Smartphone instance. Then ask AI to explain the MRO and why Python found the method it found.


Inspecting MRO with mro and mro()

Python gives you two ways to inspect MRO:

Loading Python environment...

Both return the same information. When debugging inheritance, print the MRO to understand the search order:

Loading Python environment...

Output:

MRO: [<class 'SmartAgent'>, <class 'Agent'>, <class 'ChatMixin'>, <class 'ToolMixin'>, <class 'object'>]
Result: Agent processing

Agent is searched first, so Agent's process() is called. If you want a different priority, change the inheritance order to class SmartAgent(ChatMixin, Agent, ToolMixin):.

✨ Teaching Tip

Use Claude Code to visualize MRO: "Draw the inheritance tree for this class hierarchy and show me the method lookup order step-by-step." This visual aid clarifies why certain methods are called.


When NOT to Use Inheritance: A Design Perspective

Inheritance is powerful but can be misused. Here's an anti-pattern:

Loading Python environment...

A Car is not an Engine; a Car has an Engine. This is a composition problem, not an inheritance problem. More on this in Lesson 3. For now, remember: inheritance should represent true "is-a" relationships.


Code Specification and Validation

Specification: Create a multi-level inheritance hierarchy (Vehicle → Car → SportsCar) with proper super() usage, method overriding, and MRO demonstration.

Prompt Used:

Create Vehicle class with make and engine_type.
Create Car(Vehicle) that adds doors.
Create SportsCar(Car) that adds top_speed.
All classes have describe() method that calls super().describe() and adds their own info.
Show MRO and test all three classes.

Generated Code (tested on Python 3.13+):

Loading Python environment...

Validation:

  • ✅ Single inheritance chain: Vehicle → Car → SportsCar
  • ✅ Each class calls super().init() correctly
  • ✅ Method overriding works: describe() builds on parent descriptions
  • ✅ MRO output shows proper linear ordering
  • ✅ All code tested on Python 3.13+

Challenge: Build an Agent Hierarchy System

In this challenge, you'll move through all four roles: discovering requirements independently, learning from AI, challenging AI's understanding, and building production code. The result: a reusable agent framework demonstrating inheritance and MRO in professional AI systems.


Part 1: Experience Inheritance Problems in Agent Systems

Your Role: System architect identifying design gaps with AI collaboration

Discovery Exercise: Exploring Code Duplication in Agent Design

Imagine you're building a multi-agent system. Each agent type (ChatAgent, CodeAgent, DataAgent) needs to process messages, but without inheritance, you'll duplicate code.

💬 AI CoLearning Prompt - Discovering the Duplication Problem

"I'm building a multi-agent system with ChatAgent, CodeAgent, and DataAgent. Each needs:

  • __init__(name, model) that sets up name, model, messages_processed
  • process(message) that processes messages (different for each agent type)
  • get_status() that returns agent info

Without inheritance, show me what the code looks like for all 3 agents. Then analyze:

  1. How many lines are duplicated across the 3 agents?
  2. If I need 100 agent types, how many times is __init__ duplicated?
  3. If there's a bug in get_status(), how many places need fixing?
  4. What Python feature would eliminate this duplication?"

Expected Understanding: AI will show you the duplicated code pattern and explain that 100 agent types = 100 duplicate __init__ methods, making bug fixes extremely risky. You'll SEE the maintenance nightmare before coding it yourself.

💬 AI CoLearning Prompt - Understanding the Scaling Problem

"In my agent system without inheritance:

  • 3 agent types = 3 duplicate init methods
  • 3 agent types = 3 duplicate get_status methods

Explain the scaling problem: What happens at 10 agent types? 50? 100? Show me the math:

  • How many total lines of duplicate initialization code?
  • If I add a new attribute to all agents (like created_at timestamp), how many places need changing?
  • What's the risk of forgetting to update one agent type?"

Expected Understanding: AI will explain exponential maintenance cost. You'll understand that each new agent type adds duplicate code, and each new shared feature requires N changes (where N = number of agent types).

💬 AI CoLearning Prompt - Previewing the Inheritance Solution

"You showed me the duplication problem. Now preview the solution:

  1. What is inheritance in Python?
  2. How would a BaseAgent class eliminate duplication?
  3. Show me how ChatAgent, CodeAgent, DataAgent inherit from BaseAgent
  4. After inheritance, if I add created_at to BaseAgent, how many classes need changing?
  5. What's the code reduction percentage (before vs after inheritance)?"

Expected Understanding: AI will show you that BaseAgent centralizes shared behavior. Adding new agents requires only specialization code, not duplicate initialization. You'll see ~60-70% code reduction.


Part 2: Learn Inheritance and MRO as the Solution

Your Role: Student learning from AI Teacher

AI Teaching Prompt

Ask your AI companion:

"I built a multi-agent system with ChatAgent, CodeAgent, and DataAgent. Each has duplicate __init__, process(), and get_status() methods. The code is unmaintainable.

How would inheritance solve this? Explain:

  1. What is a base class? How does it eliminate duplication?
  2. How do subclasses inherit from a base class and add specialized behavior?
  3. What is super() and why is it critical for initialization?
  4. If I have multiple parents (multiple inheritance), how does Python know which parent method to call? What is Method Resolution Order (MRO)?
  5. Show me the same agent system using inheritance with a BaseAgent class."

Expected AI Response Summary

AI will explain:

  • Base Class: A template that defines common attributes and methods
  • Subclass: Inherits everything from base, adds specialization
  • super(): Gateway to parent class methods—ensures correct initialization
  • MRO: Python's algorithm for searching parent classes in hierarchies
  • Inheritance code: Typically 40% less duplication

AI will show code like:

Loading Python environment...

Convergence Activity

After AI explains, verify understanding:

"In your inheritance solution, explain how 100 agent types would inherit from BaseAgent. Show me how adding a new bug fix to get_status() would automatically apply to all 100 agent types. Walk me through the MRO for a Smartphone class that inherits from Phone and Computer (diamond inheritance)."

Deliverable

Write 1-paragraph summary: "How Inheritance Solves Agent Duplication" explaining the base class pattern and why MRO prevents the diamond problem.


Part 3: Challenge AI with Design Edge Cases

Your Role: Student testing AI's understanding

Challenge Design Scenarios

Ask AI to handle these cases:

Challenge 1: super() Initialization Chain

"I have this hierarchy: BaseAgent → SpecializedAgent → CustomChatAgent (3-level inheritance). Write init methods using super() correctly so all three initialize properly. Then show what happens if the middle class (SpecializedAgent) forgets to call super().init()."

Expected learning: AI explains the initialization chain and why forgetting super() breaks inheritance.

Challenge 2: Diamond Inheritance with MRO

"Create Processor (has process() method), TextProcessor (Processor, adds text logic), CodeProcessor (Processor, adds code logic), UniversalProcessor (TextProcessor, CodeProcessor). Implement process() in all classes using super(). Call .mro() and explain the search order. What problem does C3 Linearization solve?"

Expected learning: AI explains why C3 ensures no class is visited twice and why order matters.

Challenge 3: MRO in Multi-Agent Coordination

"I have BaseAgent with execute(). I want ChatMixin (adds chat capability), ToolMixin (adds tool capability), and SmartAgent(ChatMixin, ToolMixin, BaseAgent). All have different execute() logic. Show the MRO and explain which execute() runs. What if the order matters—how would I change it?"

Expected learning: AI shows that inheritance order in class SmartAgent() determines search priority.

Deliverable

Document your three challenges, AI's responses, and analysis of whether AI's explanations were complete and accurate.


Part 4: Build Agent Hierarchy Framework for Production

Your Role: Knowledge synthesizer creating reusable code

Your Agent Framework

Create agent_framework.py with a complete, production-ready agent system:

Loading Python environment...

Your task: Expand this framework with:

  1. Add 2-3 more specialized agent types (ImageAgent, APIAgent)
  2. Implement a mechanism to track which agents have processed messages
  3. Create a test that demonstrates MRO by printing .mro() for each agent class
  4. Add documentation showing this scales to 100+ agent types with zero duplication

Validation Checklist

  • ✅ BaseAgent defines the contract
  • ✅ All subclasses call super() properly
  • ✅ No code duplication across agent types
  • ✅ Adding a new agent type requires <10 lines of code
  • ✅ Bug fix in BaseAgent applies to all agents automatically

Deliverable

Complete agent_framework.py with working implementation and docstring explaining:

  • Why BaseAgent reduces code duplication
  • How super() ensures proper initialization
  • What happens when you add a new agent type
  • How MRO works in your agent hierarchy

Try With AI

How would you refactor a 100-agent system where each agent duplicates the same initialization logic?

🔍 Explore Inheritance Patterns:

"Show me how BaseAgent eliminates duplication across ChatAgent, CodeAgent, and DataAgent. Explain why fixing a bug in BaseAgent's init method automatically fixes all subclasses."

🎯 Practice Method Resolution Order:

"Create a diamond inheritance scenario with BaseProcessor, TextMixin, CodeMixin, and UniversalProcessor. Call .mro() and explain which method executes first when I call process()."

🧪 Test super() Chains:

"Write a 3-level inheritance hierarchy where each level adds initialization logic. Show what breaks when the middle class forgets super().init() and explain why."

🚀 Apply to Multi-Agent Architecture:

"Design an agent framework where I can add 20 new agent types without duplicating common behavior. Include error tracking, message history, and performance metrics in the base class."