【问题标题】:diamond inheritance of classes with same members in python and with super在 python 和 super 中具有相同成员的类的菱形继承
【发布时间】:2012-02-22 20:50:21
【问题描述】:

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

我在编写类时使用的方法是从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,这是一个很好的功能,因为它可以防止我在实例化以下任何对象时输入无效参数。

我还注意到,如果我在设置变量之前有 super 行,那么问题就解决了,因为最高级别的对象将覆盖较低的级别。然而,我的代码大量构建在最后,因为所有实际的“设置”都是由低级类执行的,而更高级别的类将值传递到继承链中。是否有关于在哪里适合家长通话的指南?

对 Stackoverflow 有什么想法吗?

谢谢

附言这只是“合作课程”的糟糕设计吗?究竟什么是合作班?有没有应该遵循的规则或指导方针?

编辑:

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

【问题讨论】:

  • 鉴于他们共享一个成员这一事实,我不知道您是如何做到这一点的。如果他们共享一个成员,他们必须有其他共同点,你不能把那个成员提取到一个公共类中吗?
  • 谢谢,这就是我最后所做的。我显然需要处理我的 OO 思维过程
  • 我觉得这是最好的 =)

标签: python inheritance super diamond-problem


【解决方案1】:

也许有更好的方法,但这应该避免覆盖::

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

【讨论】:

  • 谢谢,我尽量远离 hasattr 或任何依赖于使用字符串获取方法/成员的东西,似乎更容易出错?另外虽然我没有提到它,但是我在 init 中使用了很多 set 方法,这些方法需要能够在后面的代码中覆盖方法
【解决方案2】:

这只是“合作类”的糟糕设计吗?

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

究竟什么是协作类?是否应该遵循规则或准则?

你已经读过的那一篇:

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

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

您可以做出选择。你可以:

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

  • 始终将所有参数向下传递。到时候你不妨把所有签名改成__init__(self, **kwargs)

  • 不要使用多重继承

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-28
    • 2011-02-07
    • 2014-07-01
    • 1970-01-01
    • 2021-11-01
    • 2016-06-08
    • 2014-01-05
    • 2021-10-31
    相关资源
    最近更新 更多