I came across the following constructor recently, but don't quite understand what a bunch of it is referencing:
class EobiExchange(L3Exchange):
def __init__(self, *args, **kwargs):
self.reference_template_data = None
super().__init__(*args, **kwargs)
- I do understand that
super().__init__()
means that it is inheriting from its Parent's Constructor? - please correct me if I am wrong! (i.e.L3Exchange
's constructor in this case) - But what I completely don't understand is what the
*args
,**kwargs
mean; I understand them in the general terms like it means you can pass in any number of arguments? But in this context I don't quite see it. Any example would be so helpful. Thanks - Lastly, if we have
class EobiExchange()
, but still usedsuper()
, what would the EobiExchange's constructor be referencing in this case? Is it other classes that have been defined within the same file but further up to this class?
CodePudding user response:
For single inheritance, your understanding of the behavior of super is essentially correct - you don't really need super when all you're dealing with is single inheritance.
For multiple inheritance it is not correct. There super will call the next class in self's MRO chain - which could be the parent, and could be a sibling class in case of diamond pattern inheritance.
Diamond inheritance pattern:
class A:
def say(self):
print('a')
class B(A):
def say(self):
super().say()
print('b')
class C(A):
def say(self):
super().say()
print('c')
class D(B, C):
def say(self):
super().say()
print('d')
d = D()
d.say()
the inhertiance graph looks like a diamond:
which prints
a
c
b
d
because the super in D calls B.say, which uses super to call C.say, which uses super to call A.say. I.e. the super call in B calls a class that B doesn't know about.
CodePudding user response:
Yes, super().__init__()
ensures that the parent's constructor gets called.
The *args, **kwargs
here are used just to "redirect" the parameters from the child's constructor to the parent's construtor. It pretty much means take any arguments and call the parent's constructor with these arguments.
As an example we could define
def my_print(*args, **kwargs):
print(*args, **kwargs)
By using *args
and **kwargs
we ensure that print receives exactly the same arguments as our function, so it is a perfect copy of the print
function. We can for example call
my_print("foo", "bar", sep=" ")
And we would receive the same exact output as if we called print
. ( "foo bar"
)
And for the third question, you can read more about it in this question. In short super()
doesn't do exactly what one might think at first and, there is always a base class, even if not explicitly mentioned (object
).