【问题标题】:What's the Pythonic way to implement "diamond inheritance"?实现“钻石继承”的 Pythonic 方式是什么?
【发布时间】:2015-08-18 14:46:23
【问题描述】:

我正面临一个几乎教科书般的钻石继承问题。下面的(相当人为的!)示例捕获了它的所有基本特征:

# CAVEAT: error-checking omitted for simplicity

class top(object):
    def __init__(self, matrix):
        self.matrix = matrix  # matrix must be non-empty and rectangular!

    def foo(self):
        '''Sum all matrix entries.'''
        return sum([sum(row) for row in self.matrix])

class middle_0(top):
    def foo(self):
        '''Sum all matrix entries along (wrap-around) diagonal.'''
        matrix = self.matrix
        n = len(matrix[0])
        return sum([row[i % n] for i, row in enumerate(matrix)])

class middle_1(top):
    def __init__(self, m, n):
        data = range(m * n)
        matrix = [[1 + data[i * n + j] for j in range(n)] for i in range(m)]

        super(middle_1, self).__init__(matrix)

总之,middle_0middle_1 类都是top 类的子类,其中middle_0 覆盖方法foomiddle_1 覆盖方法__init__。基本上,经典的钻石继承设置。对基本模式的一种阐述是middle_1.__init__ 实际上调用了父类的__init__。 (下面的演示展示了这些类的实际应用。)

我想定义一个类bottom,它从middle_0“获取”1foo 和从middle_1 获取__init__

实现这样一个bottom 类的“pythonic 方式”是什么?


演示:

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print top(matrix).foo()
# 45
print middle_0(matrix).foo()
# 15
print middle_1(3, 3).foo()
# 45

# print bottom(3, 3).foo()
# 15

1我写的是“gets”而不是“inherits”,因为我怀疑这个问题不能用标准的 Python 继承轻松解决。

【问题讨论】:

标签: python oop inheritance


【解决方案1】:

bottom 只是继承自两者;您的课程没有什么特别之处可以使这种情况变得特别:

class bottom(middle_0, middle_1):
    pass

演示:

>>> class bottom(middle_0, middle_1):
...     pass
... 
>>> bottom(3, 3).foo()
15

这按预期工作,因为 Python 安排 middle_0middle_1top 之前搜索方法是:

>>> bottom.__mro__
(<class '__main__.bottom'>, <class '__main__.middle_0'>, <class '__main__.middle_1'>, <class '__main__.top'>, <type 'object'>)

这显示了类的方法解析顺序;正是用于查找方法的顺序。所以bottom.__init__middle_1 上找到,bottom.foomiddle_0 上找到,因为两者都列在top 之前。

【讨论】:

  • 感谢您的详细解释。我必须得出结论,我的示例以某种方式缺少我的实际问题的功能,导致该解决方案在我尝试时失败(并提示我发布问题)。我正在使用的代码非常大/复杂,因此发布它是不切实际的......我必须进一步调查。
  • @kjo 适用相同的原则;您需要查看 MRO 才能找到方法。
【解决方案2】:

我觉得

从 middle_0 “获取”1 foo 和从 middle_1 “获取”__init__ 的类底部。

将由

简单地完成
class bottom(middle_0, middle_1):
    pass

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    相关资源
    最近更新 更多