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

Множественное наследование в python3 с разными сигнатурами

У меня есть три класса: A, B и C.

C наследуется от A и B (в этом порядке). Подписи конструктора A и B различны. Как я могу вызвать методы __init__ обоих родительских классов?

Моя работа в коде:

class A(object):
    def __init__(self, a, b):
        super(A, self).__init__()
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q):
        super(B, self).__init__()
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        super(A, self).__init__(1, 2)
        super(B, self).__init__(3)

c = C()

дает ошибку:

Traceback (most recent call last):
  File "test.py", line 16, in <module>
    c = C()
  File "test.py", line 13, in __init__
    super(A, self).__init__(1, 2)
TypeError: __init__() takes 2 positional arguments but 3 were given

Я нашел этот ресурс, который объясняет множественное наследование с помощью разных наборов аргументов, но они предлагают использовать *args и **kwargs для использования для всех аргументов. Я считаю это очень уродливым, так как я не вижу из вызова конструктора в дочернем классе, какие параметры я передаю родительским классам.

4b9b3361

Ответ 1

Используйте не super(baseclass, ...), если не знаете, что делаете. Первый аргумент super() сообщает ему, что класс пропустить при поиске следующего метода. Например. super(A, ...) будет смотреть MRO, найти A, а затем начать поиск __init__ в базовом классе next, не A. Для C MRO имеет значение (C, A, B, object), поэтому super(A, self).__init__ найдет B.__init__.

В этих случаях вы не хотите использовать совместное наследование, но вместо этого ссылаетесь непосредственно на A.__init__ и B.__init__. super() следует использовать только в том случае, если методы, которые вы вызываете, имеют одну и ту же подпись или будут проглатывать неподдерживаемые аргументы с помощью *args и **vargs. В этом случае потребуется только один вызов super(C, self).__init__(), а следующий класс в заказе MRO позаботится о цепочке вызова.

Поменяв это иначе: когда вы используете super(), вы не можете знать, какой класс будет следующим в MRO, чтобы класс лучше поддерживал аргументы, которые вы передаете ему. Если это не так, не используйте super().

Вызов методов базы __init__ напрямую:

class A(object):
    def __init__(self, a, b):
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q):
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        # Unbound functions, so pass in self explicitly
        A.__init__(self, 1, 2)
        B.__init__(self, 3)

Используя кооператив super():

class A(object):
    def __init__(self, a=None, b=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        super().__init__(a=1, b=2, q=3)