在python和super中具有相同成员的类的钻石继承

时间:2012-02-22 20:50:22

标签: python inheritance super diamond-problem

我发现自己处于钻石继承的奇怪情况,更糟糕的是,钻石中间的阶层共享一个成员。下面我展示了一段代码,突出了我的问题。

我在编写类的过程中使用的方法,我从http://rhettinger.wordpress.com/2011/05/26/super-considered-super/学习了这个类,它链接在python文档站点上,用于内置函数super

class A(object):
    pass

class B(A):
    def __init__(self, z=None, **kwargs):
        self.z = z
        super(B, self).__init__(**kwargs)
        # super(B, self).__init__(z=z, **kwargs)

class C(A):
    def __init__(self, z=None, **kwargs):
        self.z = z
        super(C, self).__init__(**kwargs)

class D(B, C):
    pass

d = D(z='y')

for arg, value in d.__dict__.iteritems():
    print arg, ':', value

给出输出

z : None

问题是使用关键字参数来确保函数匹配的签名的方法从类C的init调用中删除了z参数。我可以强制将参数添加回kwargs(参见注释代码),但这导致我无法实例化类型B的对象,因为这将导致调用对象的init,该对象不带参数,这是一个很好的功能,因为它可以防止我在实例化任何下面的对象时输入无效的参数。

另外我注意到如果在设置变量之前我有超线,则问题是固定的,因为最高级别的对象将覆盖较低级别。然而,由于所有实际的“设置”都由低级别的类执行,而较高级别的类传递了要设置为继承链的值,因此我的代码大量构建在最后具有超级。是否有适合父母电话的指导方针?

任何想法Stackoverflow?

感谢

P.S。这只是“合作班级”的糟糕设计吗?究竟什么是合作班级?是否应遵循规则或指导原则?

编辑:

Stackoverflow不会让我回答我自己的问题,但我想出了一个解决方案。

我认为合作班级之间不应该有任何共享成员。如果有两个彼此独立的类(在某种意义上没有'是一种'关系)共享一个成员那么你应该在继承关系中添加一个抽象级别。

应该取出共享成员并将其放入一个单独的类中,该类继承自共享基类,并继承自钻石中的类。

以下是更正后的代码。为了与OP中的链接保持一致,我引入了一个Root基类

我应该指出,我没有正式的编程教育(就像我猜的那样),如果我使用错误的术语,请道歉。

class Root(object):
    pass

class A(Root):
    pass

class HasAZ(Root):
    def __init__(self, z=None, **kwargs):
        self.z = z
        super(HasAZ, self).__init__(**kwargs)

class B(HasAZ, A):
    pass


class C(HasAZ, A):
    pass

class D(B, C):
    pass

d = D(z='y')

for arg, value in d.__dict__.iteritems():
    print arg, ':', value

2 个答案:

答案 0 :(得分:1)

也许有更好的方法可以做到这一点,但这应该避免覆盖::

class C(A):
    def __init__(self, z=None, **kwargs):
        if not hasattr(self, 'z'):
            self.z = z
        super(C, self).__init__(**kwargs)

答案 1 :(得分:1)

  

这只是一个糟糕的合作班级设计'

是的,特别是因为属性冲突。如果您没有使用相同名称的属性,那么到目前为止B.z不会被C.z覆盖。

  

究竟什么是合作班?是否应遵循规则或指导原则?

你已经读过的那个:

http://rhettinger.wordpress.com/2011/05/26/super-considered-super/

据我所知,这是合作班级规则/指南的最佳来源。

你可以选择。你可以:

  • 在继承树的所有类中使您的属性名称唯一

  • 总是将所有参数传递给树。此时,您也可以将所有签名更改为__init__(self, **kwargs)

  • 不要使用多重继承