Как вызвать конструктор каждого родителя ровно один раз? - PullRequest
3 голосов
/ 06 марта 2019

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

class A:
    def __init__(self):
        print("Started A's constructor")
        # -- Not calling: super().__init__() --
        print("Ended A's constructor")

class B:
    def __init__(self):
        print("Started B's constructor")
        super().__init__()
        print("Ended B's constructor")

class C(A, B):
    def __init__(self):
        print("Started C's constructor")
        super().__init__()
        print("Ended C's constructor")

После вызова

c = C()

мы получаем вывод

Started C's constructor
Started A's constructor
Ended A's constructor
Ended C's constructor

Если я хочу вызвать оба конструктора базового класса для каждого объекта C, и у меня нет доступа к базовому классу для добавления super().__init__() вызов, что нужно изменить или добавить к C?Есть ли способ сделать это так, чтобы он не сломался, если A действительно вызвал super().__init__()?(Изменить: для ясности, добавление super().__init__() к A вызовет конструктор B, следующий за ним в MRO; чтобы сделать это более понятным: пример кода )

Что еще более важно, в общем случае, когда каждый хочет вызвать каждый __init__ метод каждого предка ровно один раз, и не был уверен в том, что каждая функция __init__ вызывает super().__init__(), как можно было бы гарантировать, что каждый родительский класс был вызван один раз итолько один раз?

Если это невозможно, не подорвет ли это фундаментальные объектно-ориентированные принципы?Просто в этом случае реализация A не должна влиять на поведение B.

Ответы [ 2 ]

1 голос
/ 06 марта 2019

A не использует super, поэтому его нельзя использовать для совместного наследования.Вместо этого определите оболочку для A, для Python's super() считается супер! .(Предполагая, что вы не можете просто исправить A во-первых.)

class A:
    def __init__(self):
        print("Started A's constructor")
        print("Ended A's constructor")


# AWrapper also needs to override each method defined by A;
# those simply delegate their work to the intenral instance of A
# For example,
#
#  def some_method(self, x, y):
#      return self.a.some_method(x, y)
#
class AWrapper:
    def __init__(self, **kwargs):
        self.a = A()
        super().__init__(**kwargs)


class B:
    ...


class C(AWrapper, B):
    ...
0 голосов
/ 06 марта 2019

Вы можете перебрать атрибут __bases__ объекта класса, чтобы вызвать метод __init__ каждого из родительских классов:

class C(A, B):
    def __init__(self):
        print("Started C's constructor")
        for base in self.__class__.__bases__:
            base.__init__(self)
        print("Ended C's constructor")

так что C() выводит:

Started C's constructor
Started A's constructor
Ended A's constructor
Started B's constructor
Ended B's constructor
Ended C's constructor
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...