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(), и это в некотором смысле, но это также просто недостаток в множественном наследовании в целом. Алмаз шаблоны наследования часто подвержены ошибкам. И многие обходные пути для них приводят к еще более запутанному и подверженному ошибкам коду. Иногда лучшим ответом является попытка рефакторинга кода для использования менее множественного наследования.