Python - инициализация родительских классов - PullRequest
0 голосов
/ 06 февраля 2019

Я пытаюсь понять, как использовать super () для инициализации родительского класса по одному на основе условия.

class A:
    def __init__(self, foo):
        self.foo = foo

class B:
    def __init__(self, bar):
        self.bar == bar

class C(A,B):
    def __init__(self):
        #Initialize class A first.
        #Do some calculation and then initialize class B 

Как использовать super () в class C так, чтобы сначала он только инициализировал class A, затем я делаю калькуляцию и вызываю super () для инициализации class B

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Вы не можете делать то, о чем просите в C.__init__, так как super не дает вам никакого контроля над тем, какие конкретные унаследованные методы вызываются, только в порядке, в котором они вызываются, и это полностью контролируетсяпорядок, в котором перечислены родительские классы.

Если вы используете super, вам необходимо использовать его последовательно в всех классах.(Вот почему это называется кооперативное наследование.) Обратите внимание, это означает, что C не может вводить какой-либо код между вызовами A.__init__ и B.__init__.

__init__ особенно сложноправильно реализовать при использовании super, потому что правило super состоит в том, что вы должны ожидать, что будут переданы произвольные аргументы, но object.__init__() не принимает никаких аргументов.Вам необходимо, чтобы каждый дополнительный аргумент «принадлежал» определенному корневому классу, который отвечает за его удаление из списка аргументов.

class A:
    def __init__(self, foo, **kwargs):
        # A "owns" foo; pass everything else on
        super().__init__(**kwargs)
        self.foo = foo

class B:
    def __init__(self, bar, **kwargs):
        # B "owns" bar; pass everything else on
        super().__init__(**kwargs)
        self.bar = bar

class C(A,B):
    def __init__(self):
        # Must pass arguments expected by A and B
        super().__init__(foo=3, bar=9)

MRO для C равно [A, B, object], поэтому дерево вызововвыглядит примерно так:

  1. C.__init__ вызывается без аргументов
  2. super() разрешается в A, поэтому A.__init__ вызывается с foo=3 и bar=9.
  3. В A.__init__, super() разрешается в B, поэтому B.__init__ вызывается с bar=9.
  4. В B.__init__, super() разрешается в object, поэтому object.__init__ вызывается без аргументов (kwargs является пустым)
  5. Как только object.__init__ возвращается, self.bar устанавливается в bar
  6. Однажды B.__init__возвращается, self.foo устанавливается на foo
  7. Как только A.__init__ возвращается, C.__init__ заканчивает

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

class A:
    def __init__(self, foo):
        self.foo = foo

class B:
    def __init__(self, bar):
        self.bar == bar

class C(A,B):
    def __init__(self):
        super(A, self).__init__(foo=3)
        # Do some calculation
        super(B, self).__init__(bar=9)

Я не совсем уверен, однако, что это не приводит к некоторым трудно предсказуемым ошибкам, которые могут проявляться с другими подклассами A, B и / или C которые пытаются использовать super правильно.

0 голосов
/ 06 февраля 2019

Вы можете явно ссылаться на базовые классы:

class A:
    def __init__(self, foo):
        self.foo = foo

class B:
    def __init__(self, bar):
        self.bar == bar

class C(A,B):
    def __init__(self):
        A.__init__(self, 'foovalue')
        # Do some calculation
        B.__init__(self, 'barvalue')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...