13.5: Multiple Inheritance and Mixin Classes
- Page ID
- 117610
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\dsum}{\displaystyle\sum\limits} \)
\( \newcommand{\dint}{\displaystyle\int\limits} \)
\( \newcommand{\dlim}{\displaystyle\lim\limits} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\(\newcommand{\longvect}{\overrightarrow}\)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\ket}[1]{\left| #1 \right>}\)
\(\newcommand{\bra}[1]{\left< #1 \right|}\)
\(\newcommand{\braket}[2]{\left< #1 \vphantom{#2} \right| \left. #2 \vphantom{#1} \right>}\)
\(\newcommand{\braopket}[3]{\left< #1 \vphantom{#2}\vphantom{#3} \right| #2 \vphantom{#1}\vphantom{#3} \left| #3 \vphantom{#1}\vphantom{#2} \right>}\)
\(\newcommand{\qmvec}[1]{\mathbf{\vec{#1}}}\)
\(\newcommand{\op}[1]{\hat{\mathbf{#1}}}\)
\(\newcommand{\expect}[1]{\langle #1 \rangle}\)
\(\newcommand{\dfn}[1]{\emph{\textbf{#1}}}\)
By the end of this section you should be able to
- Construct a class that inherits from multiple superclasses.
- Identify the diamond problem within multiple inheritance.
- Construct a mixin class to add functionality to a subclass.
Multiple inheritance basics
Multiple inheritance is a type of inheritance in which one class inherits from multiple classes. A class inherited from multiple classes has all superclasses listed in the class definition inheritance list. Ex: class SubClass(SuperClass_1, SuperClass_2).
Consider the program:
class A:
def __init__(self, a_attr=2):
self.a_attr = a_attr
class B:
def __init__(self, b_attr=4):
self.b_attr = b_attr
class C(A, B):
def __init__(self, a_attr=5, b_attr=10, c_attr=20):
A.__init__(self, a_attr)
B.__init__(self, b_attr)
self.c_attr = c_attr
b_inst = B(2)
c_inst = C(1, 2)
What is the value of c_inst.a_attr?
15Error
- Answer
-
a.
1is the argument passed toC's__init__()fora_attr.
What is the value of c_inst.c_attr?
220Error
- Answer
-
b. An argument is not passed to
C's__init__()forc_attr, soc_attris assigned with the default value,20.
What is the value of b_inst.a_attr?
24Error
- Answer
-
a.
2maps tob_attrinB's__init__().
The diamond problem and mixin classes
Multiple inheritance should be implemented with care. The diamond problem occurs when a class inherits from multiple classes that share a common superclass. Ex: Dessert and BakedGood both inherit from Food, and ApplePie inherits from Dessert and BakedGood.
Dessert and Baked Good override a Food method, the overridden Food method that Apple Pie inherits is ambiguous. Thus, diamond shaped inheritance should be avoided.Mixin classes promote modularity and can remove the diamond problem. A mixin class:
- Has no superclass
- Has attributes and methods to be added to a subclass
- Isn't instantiated (Ex: Given
MyMixinclass,my_inst = MyMixin()should never be used.)
Mixin classes are used in multiple inheritance to add functionality to a subclass without adding inheritance concerns.
The following code isn't correct, as not all plants are carnivorous. Follow the programmer through the programmer's edits to improve the program. Note: Rose, Pitcher, and VenusFlyTrap represent plants that all photosynthesize. Pitcher and VenusFlyTrap represent plants that are also carnivorous and can eat.
A pass statement is used in Python to indicate that code is to be written later and prevents certain errors that would result if no code was written or a comment was used instead.
class Plant:
def photosynth(self):
print("Photosynthesizing")
def eat(self):
print("Eating")
class Rose(Plant):
pass
class Pitcher(Plant):
pass
class VenusFlyTrap(Plant):
pass
Which edit is appropriate?
- Move
eat()to a different class. - Remove
Plantas a superclass.
- Answer
-
a.
eat()only applies to carnivorous plants, whichPitcherandVenusFlyTraprepresent.
The programmer edits the code as follows. How can the program be improved?
class Plant:
def photosynth(self):
print("Photosynthesizing")
class Rose(Plant):
pass
class Pitcher(Plant):
def eat(self):
print("Eating")
class VenusFlyTrap(Plant)
def eat(self):
print("Eating")
- Move
photosynth()intoRose. - Remove redundancy of
eat().
- Answer
-
b.
eat()can be moved into a mixin class included inPitcher's andVenusFlyTrap's inheritance list.
The programmer edits the code to create a mixin class containing eat(). Which class name, replacing X, is most appropriate for the mixin?
class Plant:
def photosynth(self):
print("Photosynthesizing")
class X:
def eat(self):
print("Eating")
class Rose(Plant):
pass
class Pitcher(Plant, X):
pass
class VenusFlyTrap(Plant, X)
pass
CarnivClassCarnivMixin
- Answer
-
- b. Good practice is to have a mixin class name end in
"Mixin"to identify the class's purpose. The final implementation is:
class Plant: def photosynth(self): print("Photosynthesizing") class CarnivMixin: def eat(self): print("Eating") class Rose(Plant): pass class Pitcher(Plant, CarnivMixin): pass class VenusFlyTrap(Plant, CarnivMixin) pass - b. Good practice is to have a mixin class name end in
The program below represents multiple inheritance and has the diamond problem. Edit the program to use a mixin class, OnlineMixin. OnlineMixin:
- Replaces
OnlineShop. - Is a superclass of
FoodFast. - Has one method,
process_online(), which prints"Connecting to server"and is called byFoodFast'sprocess_order().
The output should match:
Processing meal order
Connecting to server
Enjoy your FoodFast order
Interactive Code
- Answer
-
class Business:
def process_order(self):
print("Processing order")class Restaurant(Business):
def process_order(self):
print("Processing meal order")class OnlineMixin():
def process_online(self):
print("Connecting to server")class FoodFast(Restaurant, OnlineMixin):
def process_order(self):
super().process_order()
self.process_online()
print("Enjoy your FoodFast order")franchise_1 = FoodFast()
franchise_1.process_order()


