python 与父 类 的多重继承有不同 __init__()

python multi inheritance with parent classes have different __init__()

这里的BC都是从A派生出来的,但是__init__()参数不同。我的问题是如何在这里写correct/elegant代码来初始化下面例子中的self.a,self.b,self.c1,self.c2? 也许另一个问题是——在 __init()__ 函数中进行此变量设置是一个好的编码习惯还是使用更简单的 __init__() 函数更好,并为每个 [=] 执行 set() 函数27=] 之后,这似乎不像在 __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)   

Python 中的多重继承要求所有 classes 协作才能使其工作。在这种情况下,您可以通过让每个 class 中的 __init__ 方法接受任意 **kwargs 并在它们调用 super().__init__.

时传递它们来使它们合作

对于您的示例 class 层次结构,您可以这样做:

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

请注意,如果您希望 D 直接使用参数值(而不是使用 self.a 等),您可以将它们作为命名参数并仍然在super() 通话:

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!

如果某些父 classes 不将参数(以其原始形式)保存为属性,那么接受并传递某些参数很重要,但您需要这些值。您还可以使用这种代码风格为某些参数传递修改后的值(例如 super(D, self).__init__(a=a, b=b, c1=2*c1, c2=5*c2, **kwargs))。

这种具有不同参数的协作多重继承几乎不可能使用位置参数来实现。但是,对于关键字参数,调用中名称和值的顺序并不重要,因此很容易同时传递命名参数和 **kwargs 而不会造成任何破坏。使用 *args 效果不佳(尽管 Python 3 的最新版本在如何使用 *args 调用函数方面更加灵活,例如允许在单个调用中进行多次解包:f(*foo, bar, *baz)).

如果您使用的是 Python 3(我假设不是,因为您明确将参数传递给 super),您可以将参数设为协作函数 "keyword-only",这将防止用户混淆并尝试使用位置参数调用您的方法。只需在参数列表中的其他命名参数之前放置一个 *def __init__(self, *, c1, c2, **kwargs):.