python multiple inheritance passing arguments to constructors using super

旧街凉风 提交于 2019-11-30 10:54:50

问题


Consider the following snippet of python code

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

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

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

class D(B, C):
    def __init__(self, a, b, c, d):
        #super(D,self).__init__(a, b, c) ???
        self.d = d

I am wondering how can I pass a, b and c to corresponding base classes' constructors.


回答1:


Well, when dealing with multiple inheritance in general, your base classes (unfortunately) should be designed for multiple inheritance. Classes B and C in your example aren't, and thus you couldn't find a proper way to apply super in D.

One of the common ways of designing your base classes for multiple inheritance, is for the middle-level base classes to accept extra args in their __init__ method, which they are not intending to use, and pass them along to their super call.

Here's one way to do it in python:

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

class B(A):
    def __init__(self,b,**kw):
        self.b=b
        super(B,self).__init__(**kw)

 class C(A):
    def __init__(self,c,**kw):
        self.c=c
        super(C,self).__init__(**kw)

class D(B,C):
    def __init__(self,a,b,c,d):
        super(D,self).__init__(a=a,b=b,c=c)
        self.d=d

This can be viewed as disappointing, but that's just the way it is.




回答2:


Unfortunately, there is no way to make this work using super() without changing the Base classes. Any call to the constructors for B or C is going to try and call the next class in the Method Resolution Order, which will always be B or C instead of the A class that the B and C class constructors assume.

The alternative is to call the constructors explicitly without the use of super() in each class.

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

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

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

class D(B, C):
    def __init__(self, a, b, c, d):
        B.__init__(self, a, b)
        C.__init__(self, a, c)
        self.d = d 

There is still a downside here as the A constructor would be called twice, which doesn't really have much of an effect in this example, but can cause issues in more complex constructors. You can include a check to prevent the constructor from running more than once.

class A(object):
    def __init__(self, a):
        if hasattr(self, 'a'):
            return
        # Normal constructor.

Some would call this a shortcoming of super(), and it is in some sense, but it's also just a shortcoming in multiple inheritance in general. Diamond inheritance patterns are often prone to errors. And a lot of the workarounds for them lead to even more confusing and error-prone code. Sometimes, the best answer is to try and refactor your code to use less multiple inheritance.



来源:https://stackoverflow.com/questions/34884567/python-multiple-inheritance-passing-arguments-to-constructors-using-super

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