Что это значит, когда родительский класс имеет супер ()? - PullRequest
1 голос
/ 21 января 2020

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

Кроме того, я знаю, что все python классы Наследовать от специального класса под названием object.

Во время изучения OOP я натолкнулся на странный пример:

class A(object):
    def __init__(self):
        print('A.__init__')
        super().__init__()

class B(object):
    def __init__(self):
        print('B.__init__')
        super().__init__()

class C(A, B):
    def __init__(self):
        print('C.__init__')
        super().__init__()

Я понимаю большую часть этого, за исключением ... почему класс A имеет super().__init__()? Это родительский класс, он не должен наследоваться от кого-либо. А специальный класс object ничего не делает, поэтому я не знаю, зачем ему это нужно.

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

Проще говоря ... зачем мне нужно использовать super() в родительском классе?

Ответы [ 2 ]

1 голос
/ 21 января 2020

Рассмотрим следующий пример:

class A:
    def __init__(self, a, **kwargs):
        print('A.__init__ called')
        self.a = a
        super().__init__(**kwargs)
        print('A.__init__ finished')

class B:
    def __init__(self, b, **kwargs):
        print('B.__init__ called')
        self.b = b
        super().__init__(**kwargs)
        print('B.__init__ finished')

class C(A, B):
    def __init__(self, c, **kwargs):
        print('C.__init__ called')
        self.c = c
        super().__init__(**kwargs)
        print('C.__init__ finished')

При создании объекта C выходные данные выглядят следующим образом:

>>> C(a=1, b=2, c=3)
C.__init__ called
A.__init__ called
B.__init__ called
B.__init__ finished
A.__init__ finished
C.__init__ finished
<__main__.C object at 0x7fd15abcab70>

Из порядка, в котором используются методы __init__ и тот факт, что они заканчиваются sh в обратном порядке, мы можем видеть, что C.__init__ вызывает A.__init__, что вызывает B.__init__. То есть, хотя A не имеет явного родительского класса (поэтому его прямым родителем является object), вызов super().__init__ в A фактически вызывает B.__init__.

Это потому, что B следующий класс после A в C порядке разрешения метода (MRO). Класс A должен вызывать super(), потому что хотя его суперкласс object, Python допускает множественное наследование, поэтому A не может гарантировать, что это последний класс перед object в MRO.

>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

См. Статью Раймона Хеттингера Python super () считается super! для более подробного объяснения MRO и "кооперативных методов множественного наследования".

0 голосов
/ 21 января 2020

Проще говоря ... зачем мне использовать super () в родительском классе?

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

С другой стороны, вам также не нужны скобки () для определения класса, и, кроме того, если вы не работаете в Python2 (что не должно быть в 2020 году, поскольку Python2 .x - это больше не поддерживается с 2020 ), вам не нужно добавлять (object) после имени класса, поскольку это было просто для классов classi c Python2, чтобы принять новый формат стиля, но в Python3 все классы - это новые классы стилей.

Итак, правильный способ отображения кода выше будет следующим:

class A:
    def __init__(self):
        print('A.__init__')
        # you don't need a super() here as class A isn't inheriting anything

class B:
    def __init__(self):
        print('B.__init__')
        # you don't need the super() here either as B also isn't inheriting anything

class C(A, B):
    def __init__(self):
        print('C.__init__')
        super().__init__()
...