假设我有一系列课程如下:
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
如果现在D是B和C,它可以实现为
class D(B,C)
__init__(self,a,b,c1,c2,d):
pass
或D
可以理解为B
和C
的组合
class D(B,C)
__init__(self,a,b,c1,c2,d):
self.b=B(a,b)
self.c=C(a,c)
似乎比多继承案例复杂一点。
嗯,现在让我们的成像class D2
由5件B
和3件C
组合而成,class D3
由D2
加上一个额外的C
(参数与D
中的参数不同),D4
由D2
和另外两个C
组成(另外2个) C
具有相同的参数,但与D2
中的参数不同。使用合成似乎D2
是好的,但D3
使用D2
和C
的继承是好的,D4
可以使用{的继承{1}}和D2
。
对我来说,使用组合的缺点是我必须编写C
而不是d.c.c1
(如在继承的情况下)来获取参数d.c1
或者我需要存储直接在D中的参数c
(除了作为c
的那个)。是否有任何哲学上一致的方式来处理这些类?谢谢!
答案 0 :(得分:2)
你必须对这样的问题得到一定程度的意见 - 我的答案是使用继承 iff 你的类被设计为继承。在所有其他情况下使用组合。在实践中,这通常意味着如果您扩展的代码存在于您的控制范围之外,请不要将其子类化,除非他们的文档谈论如何您可以有效地将其子类化。
在这种情况下,由于您似乎是类层次结构的作者,继承似乎有意义(尽管您的一些断言不正确 - D
并不像您想象的那样容易实现因为没有超级类__init__
会被调用。您可能应该熟悉Raymond Hettinger的"super considered super" article
class A(object):
def __init__(self, a, **kwargs):
super(A, self).__init__(**kwargs)
self.a = a
class B(A):
def __init__(self, b, **kwargs):
super(B, self).__init__(**kwargs)
self.b = b
class C(A):
def __init__(self, c1, c2, **kwargs):
super(c, self).__init__(**kwargs)
self.c1 = c1
self.c2 = c2
现在 D
的实现非常简单:
class D(B, C):
pass
请注意,我们甚至不需要定义__init__
,因为超类的所有构造函数都可以接受任意关键字参数。实例化D
看起来像:
d = D(a='a', b='b', c1='c1', c2='c2')