multiple inheritance
#Multiple inheritance and MixIn mode in oop
Inheritance is the most commonly used code reuse method in oop (OOP), but once the classification dimensions increase, the shortcomings of single inheritance will be exposed. This article uses animal design as a clue to take you from the simplest inheritance to experience类爆炸The pain points eventually led to the best practices of Python multiple inheritance and MixIn mode.
1. Basic dilemma of inheritance
1.1 A simple single inheritance hierarchy is fine
Let's say we want to model four animals:
- 🐶 Dog - dog
- 🦇 Bat - bat
- 🦜 Parrot - Parrot
- 🦢 Ostrich - ostrich
If you prioritize by biological classification, the single inheritance structure is very clear:
All mammals inheritMammal, all birds inheritBird, well-organized and well maintained.
1.2 When behavioral classification is mixed in...
But the reality is that we not only care about what animals are biologically, but also what they can do: can they run or fly? Should we eat meat or grass? Multi-dimensional classification Once superimposed, single inheritance will be stretched.
2. "Classification explosion" of single inheritance
2.1 Try another dimension
If we don't focus on biological classification, but first look at behavior, for example, first divide it into "things that can run" and "things that can fly":
Here comes the problem: in this way, the "viviparous" characteristic common to mammals and the "oviparous" characteristic common to birds will be lost.AnimalAre they handled uniformly? Impossible, because dogs and bats are mammals and birds and cannot be placed under the same tree branch.
2.2 Two dimensions together: the number of classes explodes
What if we simply put biological type and behavioral type into an inheritance system at the same time?
In order to support "mammals + able to run", "mammals + able to fly", "birds + able to run", "birds + able to fly", we had to add 4 intermediate classes out of thin air. These are only two dimensions. What if we add dimensions such as "carnivorous/plant-eating" and "domesticated/wild"? The number of classes grows exponentially and the code quickly becomes unmaintainable.
3. Python’s multiple inheritance solution
Fortunately, Python is one of the few mainstream languages that natively supports multiple inheritance, which can break this deadlock: retain a clear "core identity main inheritance line", and additional behavioral/functional dimensions are made into independent parent classes.
In this way, dogs are still mammals, but they also have the ability to run; bats are mammals, but they have the ability to fly. Clear main identity and free combination of functions.
4. Standardize into a pattern: MixIn
Although multiple inheritance is easy to use, it can easily become confusing when there are too many parent classes - problems such as method resolution order (MRO), conflict of methods with the same name, and blurred responsibility boundaries may arise at any time. For this reason, the MixIn (mixing) mode has been derived in the industry.
4.1 Core Rules of MixIn
- The main inheritance line must be single: there can only be one parent class representing the core identity/entity (e.g.
MammalorBird)。 - MixIn classes only provide purely functional additions, they should not be instantiated individually, and generally do not hold a large amount of state.
- Name with unified suffix: commonly used by the Python community
MixIn、MixinorFeature, used uniformly hereMixIn。 - Inheritance order: The main identity is always placed as the first parameter.
Rewrite the example just now according to the rules and add a new oneCarnivorousMixIn(Carnivorous function):
4.2 Does the order have any impact?
If methods with the same name are defined in the main identity class and the MixIn class, Python will determine the calling order according to the C3 linearization algorithm. As long as you always put the main identity class first, there's usually no problem. Keep one thing in mind for daily use: Start with the main identity, followed by MixIn.
5. MixIn instance of the standard library
The MixIn pattern is not just on paper, its shadow can be seen everywhere in the Python standard library. The most classic is undoubtedlysocketserverModule:
This is the power of MixIn: Without modifying the code of the core service, you can quickly combine different service modes through just the mixing function.
6. MixIn enhancements for modern Python
In Python 3.5+, we can use Abstract Base Class (ABC) and Type Hints to make MixIn more standardized and safe.
6.1 Methods that need to be implemented to use ABC to constrain MixIn
hereFlyableMixIndeclares an abstract methodfly(), any subclass that inherits it cannot be instantiated if it does not implement it. This ensures complete functionality at the grammatical level.
6.2 Use Protocol to implement more flexible type checking
If you don't want to force ABC inheritance, you can usetyping.Protocol(Python 3.8+) Do structured type checking:
In this way, static type checking tools (such as mypy) will determine whether the types match based on the actual implementation, without having to rely heavily on inheritance relationships at runtime.
7. Don’t let MixIn “go crazy” – composition is better than inheritance
MixIn is flexible, but if too much functionality is mixed into a class (e.g. more than 3), the inheritance chain can become as elusive as "diamond inheritance". Even if Python's MRO could resolve conflicts, maintenance costs would skyrocket. At this time, the composition mode is a better choice: encapsulate the function into an independent object and use it as an attribute of the class instead of mixing it in through inheritance.
The advantage of this way of writing is that the relationship is clear, the responsibilities are independent, and the functions can be replaced or tested at any time.
Summarize
- Single inheritance is very refreshing in a single dimension, but it can easily cause class explosion when faced with multiple dimensions (species + behavior + feeding habits...).
- Multiple inheritance is a solution given by Python, which can retain a main inheritance line and make the remaining functions into separate parent classes.
- MixIn pattern is an engineering specification for multiple inheritance:
- Single primary identity,
MixInOnly add functions, add a suffix to the name, and put the main identity first.
- Python standard library (such as
socketserver) makes extensive use of MixIn mode, proving its usefulness. - Modern Python can use ABC / Protocol to enhance MixIn’s constraints and type safety.
- When there are too many functions mixed in, combination is better than inheritance and the functions are separated into independent objects, making the design more flexible and easier to maintain.
MixIn is a sharp blade given to us by Python. Use it well to write highly reusable and clear code; but any sharp tool must be measured - flexible use and careful combination are the most elegant practices.

