Consider the following python code:
class Parent(object):
def __init__(self, name, serial_number):
self.name = name
self.serial_number = serial_number
class ChildA(Parent):
def __init__(self, name, serial_number):
self.name = name
self.serial_number = serial_number
super(ChildA, self).__init__(name = self.name, serial_number = self.serial_number)
def speak(self):
print("I am from Child A")
class ChildB(Parent):
def __init__(self, name, serial_number):
self.name = name
self.serial_number = serial_number
super(ChildB, self).__init__(name = self.name, serial_number = self.serial_number)
def speak(self):
print("I am from Child B")
class GrandChild(ChildA, ChildB):
def __init__(self, a_name, b_name, a_serial_number, b_serial_number):
self.a_name = a_name
self.b_name = b_name
self.a_serial_number = a_serial_number
self.b_serial_number = b_serial_number
super(GrandChild, self).__init_( something )
When running the super
function in GrandChild, what is the proper way to format the __init__
arguments so that ChildA and ChildB both get the correct arguments?
Also how do you access the two different versions of the speak
method (ChildA's version and ChildB's version) from within the GrandChild class?
The Diamond Problem is fixed using virtual inheritance, in which the virtual keyword is used when parent classes inherit from a shared grandparent class. By doing so, only one copy of the grandparent class is made, and the object construction of the grandparent class is done by the child class.
How to Solve Diamond Problem in Python? Because of the method resolution order ( __mro__ ) in Python, the ambiguity of the diamond problem in Python becomes irrelevant. The method resolution order in Python is the order in which a method is searched for in the class hierarchy, in case of inheritance.
Method Resolution Order in Python In the multiple inheritance scenario, any specified attribute is searched first in the current class. If not found, the search continues into parent classes in depth-first, left-right fashion without searching the same class twice.
The "diamond problem" (sometimes referred to as the "Deadly Diamond of Death") is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C.
so, when you call super from the grandchild, ChildA
's __init__
method will be called because super follows the __mro__
property (parents left to right then grandparents left-to-right, then great grandparents, ...)
Since ChildA
's init also calls super, then all the super calls will be chained, calling child b's __init__
and eventually the parent init.
For that to work, your interface generally needs to be consistent. That is positional arguments need to mean the same things, and be in the order.
In situations where that's not the case, keyword arguments may work better.
class Parent:
def __init__(self, name, serial, **kwargs):
self.name = name
self.serial = serial
class ChildA(Parent):
def __init__(self, a_name, a_serial, **kwargs):
self.a_name = a_name
self.a_serial = a_serial
super().__init__(**kwargs)
class ChildB(Parent):
def __init__(self, b_name, b_serial, **kwargs):
self.b_name = b_name
self.b_serial = b_serial
super().__init__(**kwargs)
class GrandChild(ChildA, ChildB):
def __init__(self):
super().__init__(name = "blah", a_name = "a blah", b_name = "b blah", a_serial = 99, b_serial = 99, serial = 30)
Also note that in your code name and serial are reused as instance properties between all the classes and that's probably not what you want.
In python, you can explicitly call a particular method on (one of) your parent class(es):
ChildA.__init__(self, a_name, a_serial)
ChildB.__init__(self, b_name, b_serial)
Note that you need to put the self
in explicitly when calling this way.
You can also – as you did – use the super()
way, which will call the "first" parent. The exact order is dynamic, but by default it will do left-to-right, depth-first, pre-order scans of your inheritance hierarchy. Hence, your super()
call will only call __init__
on ChildA
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With