python множественное наследование, передающее аргументы конструкторам с использованием super
рассмотрим следующий фрагмент кода python
class A(object):
def __init__(self, a):
self.a = a
class B(A):
def __init__(self, a, b):
super(B, self).__init__(a)
self.b = b
class C(A):
def __init__(self, a, c):
super(C, self).__init__(a)
self.c = c
class D(B, C):
def __init__(self, a, b, c, d):
#super(D,self).__init__(a, b, c) ???
self.d = d
мне интересно, как я могу пройти a
, b
и c
конструкторам соответствующих базовых классов.
спасибо,
2 ответов
ну, при работе с множественным наследованием в общем, ваши базовые классы (к сожалению) должны быть предназначен для множественного наследования. Классы B
и C
в вашем примере нет, и поэтому вы не могли найти правильный способ применить super
на D
.
одним из распространенных способов разработки базовых классов для множественного наследования является то, что базовые классы среднего уровня принимают дополнительные args в своих __init__
метод, который они не претендуют использовать, и передать их вместе с их super
звонок.
вот один из способов сделать это в python:
class A(object):
def __init__(self,a):
self.a=a
class B(A):
def __init__(self,b,**kw):
self.b=b
super(B,self).__init__(**kw)
class C(A):
def __init__(self,c,**kw):
self.c=c
super(C,self).__init__(**kw)
class D(B,C):
def __init__(self,a,b,c,d):
super(D,self).__init__(a=a,b=b,c=c)
self.d=d
это можно рассматривать как разочарование, но так оно и есть.
к сожалению, нет способа сделать эту работу с помощью super()
без изменения базовых классов. Любой вызов конструкторов для B
или C
собирается попробовать и вызвать следующий класс в Порядок Разрешения Метода, который всегда будет B
или C
вместо A
класс B
и C
конструкторы класса взять на себя.
альтернативой является вызов конструкторов явно без использования super()
в каждом класс.
class A(object):
def __init__(self, a):
object.__init__()
self.a = a
class B(A):
def __init__(self, a, b):
A.__init__(self, a)
self.b = b
class C(object):
def __init__(self, a, c):
A.__init__(self, a)
self.c = c
class D(B, C):
def __init__(self, a, b, c, d):
B.__init__(self, a, b)
C.__init__(self, a, c)
self.d = d
здесь все еще есть недостаток, как A
конструктор будет вызван дважды, что на самом деле не имеют большого эффекта в этом примере, но может вызвать проблемы в более сложных конструкторов. Вы можете включить проверку, чтобы предотвратить запуск конструктора более одного раза.
class A(object):
def __init__(self, a):
if hasattr(self, 'a'):
return
# Normal constructor.
некоторые назвали бы это недостатком super()
, и это в некотором смысле, но это также просто недостаток в множественном наследовании в целом. Алмаз шаблоны наследования часто подвержены ошибкам. И многие обходные пути для них приводят к еще более запутанному и подверженному ошибкам коду. Иногда лучшим ответом является попытка рефакторинга кода для использования менее множественного наследования.