Gere
Gere

Reputation: 12697

Call all __init__ but once in Python

I have a structure like

class A:
    def __init__(self, x):
        self.a=x

class B(A):
    def __init__(self, x):
        self.b=x

class C(A):
    def __init__(self, x):
        self.c=x

class D(B,C):
    def __init__(self, x):
        self.d=x

Now I'd like to extend the __init__s such that both B and C will call A, too (B and C can be used as stand-alone classes). Moreover D should call A, B and C (D combines features from B and C but still needs to run all initializations). All __init__ take the same parameter. Obviously A should be called only once.

Do you see an easy way to do that?

Upvotes: 2

Views: 164

Answers (2)

mgilson
mgilson

Reputation: 309949

Use super. As far as I'm aware, this is it's purpose ...

First, some proposed reading:

  • Super considered harmful and super (simultaneously -- by different people)

Next, an example:

class A(object):
    def __init__(self, x):
        print "Called A"
        self.a=x

class B(A):
    def __init__(self, x):
        print "Called B"
        super(B,self).__init__(x)
        self.b=x

class C(A):
    def __init__(self, x):
        print "Called C"
        super(C,self).__init__(x)
        self.c=x

class D(B,C):
    def __init__(self, x):
        print "Called D"
        super(D,self).__init__(x)        
        self.d=x


foo = D(10)

As stated in the comments, you often see methods which use super defined to accept any number of positional and keyword arguments:

def mymethod(self,*args,**kwargs):
    super(thisclass,self).method(*args,**kwargs)
    ...

As that allows super to pass the necessary/unnecessary arguments on to other objects in the inheritance chain. Those methods can then decide which arguments they need and ignore the rest (passing them on to the next super of course)


Finally, to complete this discussion, we need to discuss python2.x vs. python3.x. In python2.x, all of your classes must be new style (they need to inherit from object eventually). In python3.x, this is automatic. And in python3.x, you can omit the arguments to super.

 super().__init__(*args,**kwargs)

However, I prefer the python2.x style as it works for both python2.x and python3.x and I'm always left wondering how super() (python3.x style) knows what object to pass to the underlying methods as self. It seems a lot more magical then even the python2.x version to me...

Upvotes: 6

Facundo Casco
Facundo Casco

Reputation: 10585

Using super

class D(B, C):
    def __init__(self, *args, **kwargs):
        super(D, self).__init__(*args, **kwargs)
        self.d = args[0]

Some explanation about super here and a related question

In Python 2 you should also inherit from object to use new style classes, and add super to your other classes too.

Upvotes: 2

Related Questions