what does *arg and **kwargs mean when when passed through a constructor?

Question:

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 used super(), 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?
Asked By: Patrick_Chong

||

Answers:

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:

enter image description here

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.

Answered By: thebjorn

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).

Answered By: FIlip Müller
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.