Python поддерживает ограниченную форму множественного наследования. В каком смысле ограничен?

в учебнике python говорится, что"Python поддерживает ограниченную форму множественного наследования".

какие ограничения?

2 ответов


помимо ответа @Matt Anderson я думаю, что ограничения на самом деле для классов старого стиля (которые учебник для Python 2.6 по-прежнему адресует).

в учебнике Python 3 текст теперь:Python также поддерживает форму множественного наследования.


я не уверен, на какие ограничения ссылался автор учебника python, но я бы предположил, что это отчасти связано с тем, как поиск метода / атрибута реализуется в python ("порядок разрешения метода" или MRO). Python использует линеаризация суперкласса C3 механизм; это для того, чтобы иметь дело с тем, что называется "Проблема Алмаз".

после того как вы ввели множественное наследование в иерархии классов, любой класс не имеет ни одного потенциального класса, от которого он наследует, он имеет только "следующий класс В MRO", даже для классов, которые ожидают, что они наследуют от некоторого класса в частности.

, если class A(object), class B(A), class C(A) и class D(B, C), затем MRO для класса D is D->B->C->A. Класс В мог быть написан, вероятно, был, думая, что он происходит от А, и когда он призывает super() на себя, он получит метод на A. Но это больше не верно; когда B вызывает super(), он получит метод на C вместо этого, если он существует.

если вы измените сигнатуры методов в переопределенных методах, это может быть проблемой. Класс B, ожидая подпись метода из класса A при вызове super, вместо этого получает метод из 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()), и" алмаз " не должен появляться только в корне иерархии классов.