Подтвердить что ты не робот

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

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

Каковы ограничения?

4b9b3361

Ответ 2

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

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

Например, если class A(object), class B(A), class C(A) и class D(B, C), то MRO для класса D составляет D->B->C->A. Класс B мог быть написан, вероятно, был, думая, что он опускается от 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. Когда он называет супер, вещи взрываются:

[<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()), а "бриллиант" не обязательно должен появляться только в корне иерархии классов.