Inheritance is an important way of object-oriented programming because through inheritance, subclasses can extend the functionality of the parent class.
Recall the design of the Animal class hierarchy and assume that we want to implement the following 4 animals:
- Dog - doggy;
- Bat - bat;
- Parrot - parrot;
- Ostrich - Ostrich.
If we categorize by mammals and birds, we can devise a hierarchy of classes like this:
But if we categorize them according to "can run" and "can fly", we should design such a hierarchy of classes:
To include both of the above categories, we would have to design more layers:
- Mammals: mammals that can run, mammals that can fly;
- Birds: birds that can run, birds that can fly.
In this way, the class hierarchy is complicated:
If we add "pet class" and "non-pet class", the number of classes will grow exponentially, and it is obvious that this design is not feasible.
The correct approach is to use multiple inheritance. First, the main class hierarchy is still designed according to mammals and birds:
class Animal(object): pass # Broad categories. class Mammal(Animal): pass class Bird(Animal): pass # Various animals. class Dog(Mammal): pass class Bat(Mammal): pass class Parrot(Bird): pass class Ostrich(Bird): pass
Now, to add more Runnable and Flyable functionality to the animal, we just need to define the Runnable and Flyable classes first:
class Runnable(object): def run(self): print('Running...') class Flyable(object): def fly(self): print('Flying...')
For animals that need Runnable functionality, inherit an additional Runnable, such as Dog:
class Dog(Mammal, Runnable): pass
For animals that need Flyable functionality, inherit an additional Flyable, such as Bat:
class Bat(Mammal, Flyable): pass
With multiple inheritance, a single subclass can get all the functionality of multiple parent classes at the same time.
Mixin
When designing class inheritance relationships, it is common for the main line to be a single inheritance, e.g., Ostrich inherits from Bird, but if additional functionality needs to be "mixed in", this can be accomplished through multiple inheritance, e.g., by having Ostrich inherit from Bird, but also from This design is often called Mixin.
To see the inheritance relationship better, we change Runnable and Flyable to RunnableMixin and FlyableMixin. similarly, you can define CarnivorousMixin for carnivores and HerbivoresMixin for phytophagous animals, allowing a given animal to have several Mixins at the same time:
class Dog(Mammal, RunnableMixin, CarnivorousMixin): pass
The purpose of Mixin is to add multiple functions to a class, so that when designing a class, we prioritize combining the functions of multiple Mixins through multiple inheritance, rather than designing multiple levels of complex inheritance relationships.
Many of the libraries that come with Python also use Mixin. For example, Python comes with two types of web services, TCPServer and UDPServer, and to serve multiple users at the same time you have to use the multiprocessing or multithreading model, which is provided by ForkingMixin and ThreadingMixin. By combining them, we can create the right service.
For example, write a TCP service in multi-process mode, defined as follows:
class MyTCPServer(TCPServer, ForkingMixin): pass
Write a UDP service in multi-threaded mode, defined as follows:
class MyUDPServer(UDPServer, ThreadingMixin): pass
If you're going to mess with a more advanced co-processing model, you can write a CoroutineMixin:
class MyTCPServer(TCPServer, CoroutineMixin): pass
In this way, we don't need a complex and large inheritance chain, we can quickly construct the required subclasses by choosing to combine the functionality of different classes.
wrap-up
Since Python allows the use of multiple inheritance, Mixin is a common design.
Languages that allow only single inheritance (such as Java) cannot use Mixin's design.