22

在 python 教程中,据说“ Python 支持有限形式的多重继承”。

有什么限制?

4

2 回答 2

12

我不确定 python 教程的作者所指的限制是什么,但我猜这部分与在 python 中实现方法/属性查找的方式有关(“方法解析顺序”或 MRO)。Python使用C3超类线性化机制;这是为了解决所谓的“钻石问题”。

一旦你在你的类层次结构中引入了多重继承,任何给定的类都没有它继承的单个潜在类,它只有“MRO 中的下一个类”,即使对于那些期望它们继承自某些类的类也是如此特别是班级。

例如,如果class A(object)class B(A)class C(A)class D(B, C),则类的 MRODD->B->C->A。B 类可能被编写,可能是,认为它是 A 的后代,当它调用super()自身时,它会获得 A 上的方法。但这不再是真的;当 B 调用 时super(),它将在 C 上获得一个方法,如果它存在的话。

如果您在重写的方法中更改方法签名,这可能是一个问题。B 类在调用 super 时期望来自 A 类的方法的签名,而是从 C 中获取一个方法,该方法可能没有该签名(从 B 类的角度来看,可能会或可能不会实现所需的行为)。

class A(object):
    def __init__(self, foo):
        print "A!"

class B(A):
    def __init__(self, foo, bar):
        print "B!"
        super(B, self).__init__(foo)

class C(A):
    def __init__(self, foo, baaz):
        print "C!"
        super(C, self).__init__(foo)

class D(B, C):
    def __init__(self, foo, bar):
        print "D!"
        super(D, self).__init__(foo, bar)

print D.mro()
D("foo", "bar")

在此代码示例中,类 B 和 C 合理地扩展了 A,并更改了它们的__init__签名,但正确地调用了它们预期的超类签名。但是当你像那样做 D 时,B 的有效“超类”变成了 C 而不是 A。当它调用 super 时,事情就会爆炸:

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>]
D!
B!
Traceback (most recent call last):
  File "/tmp/multi_inherit.py", line 22, in <module>
    D("foo", "bar")
  File "/tmp/multi_inherit.py", line 19, in __init__
    super(D, self).__init__(foo, bar)
  File "/tmp/multi_inherit.py", line 9, in __init__
    super(B, self).__init__(foo)
TypeError: __init__() takes exactly 3 arguments (2 given)

其他方法也可能发生同样的事情(如果它们调用super()),并且“钻石”不必只出现在类层次结构的根部。

于 2012-05-20T16:21:13.790 回答
5

除了@Matt Anderson 的回答之外,我认为这些限制实际上是针对旧式类(Python 2.6 的教程仍然解决)。

在 Python 3 教程中,文本现在是:Python 也支持一种多重继承形式

于 2012-05-21T12:44:51.213 回答