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