python multi inheritance with parent classes have different __init__()

。_饼干妹妹 提交于 2019-12-07 02:12:27

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!