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

Python multiple inheritance передаёт аргументы конструкторам, использующим 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 конструкторам соответствующих базовых классов.

4b9b3361

Ответ 1

Ну, имея дело с множественным наследованием в целом, ваши базовые классы (к сожалению) должны быть разработаны для множественного наследования. Классы B и C в вашем примере отсутствуют, и поэтому вы не смогли найти правильный способ применения super в D.

Один из распространенных способов проектирования базовых классов для множественного наследования заключается в том, что базовые классы среднего уровня принимают дополнительные аргументы в свой метод __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

Это можно считать разочаровывающим, но это так, как есть.

Ответ 2

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

Ответ 3

"Мне интересно, как я могу передать a, b и c конструкторам соответствующих базовых классов". Вы можете сделать это двумя способами: Первый (как в ответе выше): B. init (self, a, b) C. init (self, a, c) Секунды: super(). init (a, b) super(). init (a, c), но атрибут будет изменен до последнего вызова, вот super(). init (a, c). Я пытался использовать MRO с конструкторами, имеющими аргументы с одинаковыми именами некоторых атрибутов, но у меня нет ответов. Кто-то может это сделать????