Множественное наследование Python: выбор супер() для вызова

Как в Python выбрать метод Parent для вызова? Скажем, я хочу вызвать метод __init__ родительского ASDF2. Похоже, мне нужно указать ASDF1 в super()..? И если я хочу вызвать __init__ ASDF3, то я должен указать ASDF2?!

>>> class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        super(ASDF1, self).__init__()


>>> ASDF()
ASDF2's __init__ happened
>>> class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        super(ASDF2, self).__init__()


>>> ASDF()
ASDF3's __init__ happened

Мне кажется бредом. Что я делаю не так?


person Name McChange    schedule 07.01.2013    source источник


Ответы (3)


super() предназначен не для этого. Super обычно выбирает одного (или всех) своих родителей в определенном порядке. Если вы хотите вызвать метод только одного родителя, сделайте это

class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        ASDF2.__init__(self)
person Falmarri    schedule 07.01.2013
comment
К сожалению, если init ссылается на какие-либо приватные методы, это не сработает. - person Erik Aronesty; 11.05.2018
comment
@ErikAronesty В Python не существует концепции частных методов, можете ли вы пояснить, что вы имеете в виду? - person Nearoo; 03.09.2018
comment
@nearoo да, если метод начинается с __, имя его метода искажено, а метод является закрытым. функция __init__ при таком вызове не будет работать с приватными методами. супер() будет. - person Erik Aronesty; 18.09.2018
comment
Какой тогда смысл в наследовании? В этом случае вам не нужно наследовать для доступа к ASDF2. Это глобальное определение. - person user32882; 20.10.2019

super вызывает следующий метод в порядке разрешения методов. В линейном дереве наследования это будет метод непосредственно родительского класса.

Здесь у вас есть три родителя, и следующий метод __init__ с точки зрения ASDF1 — это метод ASDF2. В общем, безопаснее всего передать первый класс в списке наследования super, если только вы не знаете, почему хотите сделать что-то еще.

Смысл всего этого в том, чтобы избавить вас от необходимости явно выбирать, какие __init__ методы вызывать. Вопрос здесь в том, почему вы не хотите вызывать все методы суперкласса __init__.

Существует довольно обширная литература по использованию super в python, и я рекомендую вам погуглить эту тему и прочитать, какие результаты.

person Marcin    schedule 07.01.2013
comment
Если у меня есть класс, который наследуется от threading.Thread и ASDF2, то при вызове super().__init__() поток не будет инициализирован и выдаст исключение: RuntimeError: thread.__init__() not called - person iggy12345; 21.05.2019

Вы передаете ASDF1 (один из ваших родительских классов) в качестве первого аргумента super(). Не делай этого. Вместо этого вы должны передать ASDF в качестве первого аргумента super().

документация по Python 2.7 для super()

Чтобы процитировать документы Python 2.7, типичный вызов суперкласса выглядит так:

class C(B):
    def method(self, arg):
        super(C, self).method(arg)

Обратите внимание, что первым аргументом super здесь является C, который является текущим классом. Не передавайте B (родительский класс) в super().

При определении порядка разрешения методов (MRO) super пропускает класс, который передается в качестве первого аргумента, и начинает смотреть на родителей и братьев и сестер этого класса. Таким образом, когда вы передали ASDF1 в качестве первого аргумента функции super(), она пропустила ASDF1 и начала поиск с ASDF2. Вот почему ASDF2 назвали __init__.


В Python 3 вам больше не нужно передавать текущий класс.

class C(B):
    def method(self, arg):
        super().method(arg)    # This does the same thing as:
                               # super(C, self).method(arg)
                               # (Python 3 only)
person Christian Long    schedule 10.09.2014