1

Here both B and C are derived from A, but with different __init__() parameters. My question is how to write the correct/elegant code here to initialize self.a,self.b,self.c1,self.c2 in the following example? Maybe another question is--is it a good coding practice to do this variable setting in __init()__ function or it is better to use simpler __init__() function, and do set() function for each class later, which seems not as simple as to just do it in __init()__?

class A(object):
    __init__(self,a):
        self.a=a
class B(A):
    __init__(self,a,b):
        super(B,self).__init__(a)
        self.b=b
class C(A):
    __init__(self,a,c1,c2):
        super(C,self).__init__(a)
        self.c1=c1
        self.c2=c2

class D(B,C)
    __init__(self,a,b,c1,c2,d):
        #how to write the correct/elegant code here to initialize self.a,self.b,self.c1,self.c2?
        #can I use super(D,self) something?
        self.d=d
        self.dd=self.a+self.b+2*self.c1+5*self.c2+3*self.d

d=D(1,2,3,4,5)   
1
  • Thank you for the comment @Karin, but the question here is different and more open. Commented Aug 28, 2016 at 0:54

1 Answer 1

2

Multiple inheritance in Python requires that all the classes cooperate to make it work. In this case, you can make them cooperate by having the __init__ method in each class accept arbitrary **kwargs and pass them on when they call super().__init__.

For your example class hierarchy, you could do something like this:

class A(object):
    __init__(self,a):  # Don't accept **kwargs here! Any extra arguments are an error!
        self.a=a

class B(A):
    __init__(self, b, **kwargs):  # only name the arg we care about (the rest go in **kwargs)
        super(B, self).__init__(**kwargs)  # pass on the other keyword args
        self.b=b

class C(A):
    __init__(self, c1, c2, **kwargs):
        super(C,self).__init__(**kwargs)
        self.c1=c1
        self.c2=c2

class D(B,C)
    __init__(self, d, **kwargs):
        super(D,self).__init__(**kwargs)
        self.d=d
        self.dd=self.a+self.b+2*self.c1+5*self.c2+3*self.d

Note that if you wanted D to use the argument values directly (rather than using self.a, etc.), you could both take them as named arguments and still pass them on in the super() call:

class D(B,C)
    __init__(self,a, b, c1, c2, d, **kwargs): # **kwargs in case there's further inheritance
        super(D,self).__init__(a=a, b=b, c1=c1, c2=c2, **kwargs)
        self.d = d
        self.dd = a + b + 2 * c1 + 5 * c2 + 3 * d   # no `self` needed in this expression!

Accepting and passing on some args is important if some of the parent classes don't save the arguments (in their original form) as attributes, but you need those values. You can also use this style of code to pass on modified values for some of the arguments (e.g. with super(D, self).__init__(a=a, b=b, c1=2*c1, c2=5*c2, **kwargs)).

This kind of collaborative multiple inheritance with varying arguments is almost impossible to make work using positional arguments. With keyword arguments though, the order of the names and values in a call doesn't matter, so it's easy to pass on named arguments and **kwargs at the same time without anything breaking. Using *args doesn't work as well (though recent versions of Python 3 are more flexible about how you can call functions with *args, such as allowing multiple unpackings in a single call: f(*foo, bar, *baz)).

If you were using Python 3 (I'm assuming not, since you're explicitly passing arguments to super), you could make the arguments to your collaborative functions "keyword-only", which would prevent users from getting very mixed up and trying to call your methods with positional arguments. Just put a bare * in the argument list before the other named arguments: def __init__(self, *, c1, c2, **kwargs):.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you @Blckknght, this is very nice explanation!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.