Вызов родительского класса __init__ с множественным наследованием, как правильно?

Скажем, у меня есть сценарий множественного наследования:

class A(object):
    # code for A here

class B(object):
    # code for B here

class C(A, B):
    def __init__(self):
        # What's the right code to write here to ensure 
        # A.__init__ and B.__init__ get called?

Есть два типичных подхода к написанию C __init__:

  1. (старый стиль ) ParentClass.__init__(self)
  2. (более новый стиль) super(DerivedClass, self).__init__()

Однако в любом случае, если родительские классы (A и B) не следуют одному и тому же соглашению, тогда код не будет работать правильно (некоторые из них могут быть пропущены или вызываться несколько раз).

Итак, еще раз, как правильно? Легко сказать «просто будьте последовательны, следуйте одному или другому», но если A или B взяты из сторонней библиотеки, что тогда? Существует ли подход, который может гарантировать вызов всех конструкторов родительского класса (и в правильном порядке, и только один раз)?

Редактировать: чтобы понять, что я имею в виду, если я это сделаю:

class A(object):
    def __init__(self):
        print("Entering A")
        super(A, self).__init__()
        print("Leaving A")

class B(object):
    def __init__(self):
        print("Entering B")
        super(B, self).__init__()
        print("Leaving B")

class C(A, B):
    def __init__(self):
        print("Entering C")
        A.__init__(self)
        B.__init__(self)
        print("Leaving C")

Тогда я получаю:

Entering C
Entering A
Entering B
Leaving B
Leaving A
Entering B
Leaving B
Leaving C

Обратите внимание, что init B вызывается дважды. Если я это сделаю:

class A(object):
    def __init__(self):
        print("Entering A")
        print("Leaving A")

class B(object):
    def __init__(self):
        print("Entering B")
        super(B, self).__init__()
        print("Leaving B")

class C(A, B):
    def __init__(self):
        print("Entering C")
        super(C, self).__init__()
        print("Leaving C")

Тогда я получу:

Entering C
Entering A
Leaving A
Leaving C

Обратите внимание, что init B никогда не вызывается. Таким образом, кажется, что если я не знаю/не контролирую инициализацию классов, от которых я наследую (A и B), я не могу сделать безопасный выбор для класса, который я пишу (С).

137
задан James Taylor 24 September 2018 в 01:14
поделиться