3

Есть ли разница между использованием super() и использованием имени родительского класса? Например:В чем разница между именем super() и родительским классом?

class Parent: 
    def __init__(self): 
     print("In parent") 
     self.__a=10 

class Child(Parent): 
    def __init__(self): 
     super().__init__()  # using super() 
     Parent.__init__(self) # using Parent class name 

c=Child() 

Есть ли внутри разница между super().__init__() и Parent.__init__(self)?

+0

'super()' разрешает вызов с использованием ** MRO ** ... –

+0

Только разные, если ваш подкласс имеет несколько суперклассов, или если вы в какой-то момент можете изменить свой подкласс для наследования с другой суперкласс. Btw, «родительский класс» не является обычной терминологией для наследования. – khelwood

+0

@khelwood: строго говоря, это неверно: если вы подклассифицируете класс с множественным наследованием, ваш 'super()' может фактически делегировать slibing, а не родительский. Он просто возвращает следующий в строке '__mro__'. –

ответ

6

Не указано этот случай. Но вообще, и особенно, когда вы используете множественное наследование, super() делегатов к следующему объекту в Метод Разрешение заказа (MRO) как указано в documentation:

super([type[, object-or-type]])

Возвращает прокси-объект, который делегирует вызов метода родительскому объекту или si bling класс типа. Это полезно для доступа к унаследованным методам , которые были переопределены в классе. Порядок поиска такой же, как и , используемый getattr(), за исключением того, что сам тип пропускается.

__mro__ атрибут типа перечисляет порядок поиска разрешения метод, используемый как getattr() и super(). Атрибут является динамическим и может меняться всякий раз, когда обновляется иерархия наследования .

(...)

(копирование, добавлена ​​полужирный)

Скажем, например, можно определить классы, как (заимствовано из this question, where the MRO is discussed in more detail):

class F: 
    def __init__(self): 
     print('F%s'%super().__init__) 
     super().__init__() 

class G: 
    def __init__(self): 
     print('G%s'%super().__init__) 
     super().__init__() 

class H: 
    def __init__(self): 
     print('H%s'%super().__init__) 
     super().__init__() 

class E(G,H): 
    def __init__(self): 
     print('E%s'%super().__init__) 
     super().__init__() 

class D(E,F): 
    def __init__(self): 
     print('D%s'%super().__init__) 
     super().__init__() 

class C(E,G): 
    def __init__(self): 
     print('C%s'%super().__init__) 
     super().__init__() 

class B(C,H): 
    def __init__(self): 
     print('B%s'%super().__init__) 
     super().__init__() 

class A(D,B,E): 
    def __init__(self): 
     print('A%s'%super().__init__) 
     super().__init__() 

Тогда __mro__ из A является:

A.__mro__ == (A,D,B,C,E,G,H,F,object) 

Теперь, если мы позвоним A(), он печатает:

A<bound method D.__init__ of <__main__.A object at 0x7efefd8645c0>> 
D<bound method B.__init__ of <__main__.A object at 0x7efefd8645c0>> 
B<bound method C.__init__ of <__main__.A object at 0x7efefd8645c0>> 
C<bound method E.__init__ of <__main__.A object at 0x7efefd8645c0>> 
E<bound method G.__init__ of <__main__.A object at 0x7efefd8645c0>> 
G<bound method H.__init__ of <__main__.A object at 0x7efefd8645c0>> 
H<bound method F.__init__ of <__main__.A object at 0x7efefd8645c0>> 
F<method-wrapper '__init__' of A object at 0x7efefd8645c0> 
<__main__.A object at 0x7efefd8645c0> 

так это означает, что в контексте A и при попытке получить __init__ что:

  • super().__init__ из A является D.__init__;
  • super().__init__D является B.__init__;
  • super().__init__ of B является C.__init__;
  • super().__init__ из C - E.__init__;
  • super().__init__E - G.__init__;
  • super().__init__ из G - H.__init__;
  • super().__init__ of H является F.__init__; и
  • super().__init__ от F является object.__init__.

Примечание таким образом, что super() делает по себе не делегатов родителю. Например, super() от D составляет B и B не является суперклассом D, поэтому действительно зависит от типа объекта (не от класса).

Теперь в случае D, то __mro__ является:

D.__mro__ = (D,E,G,H,F,object) 

Если мы строим D однако мы получаем:

D<bound method E.__init__ of <__main__.D object at 0x7efefd864630>> 
E<bound method G.__init__ of <__main__.D object at 0x7efefd864630>> 
G<bound method H.__init__ of <__main__.D object at 0x7efefd864630>> 
H<bound method F.__init__ of <__main__.D object at 0x7efefd864630>> 
F<method-wrapper '__init__' of D object at 0x7efefd864630> 

Так в контексте D он считает, что:

  • super().__init__ от D - E.__init__;
  • super().__init__E - G.__init__;
  • super().__init__ из G - H.__init__;
  • super().__init__ of H является F.__init__; и
  • super().__init__ от F является object.__init__.

Так вот super() из D приводит к E (для __init__) которая не то же самое в контексте A.

+1

Я думаю, вы пропустили самые важные часть там, закончив последнее предложение слишком рано: 'super()' в 'A' будет делегировать' D', а вызов 'super()' в 'D' будет делегировать' B', тогда как если бы вы начали с ' D' instance, его вызов 'super()' переходит в 'E'. – Duncan

+0

@ Duncan: совсем нет, см. Обновленный ответ. –

+1

Да, ваше редактирование с моим комментарием. Гораздо лучше, хотя я все же думаю, что было бы полезно показать, что для прямого D-экземпляра 'super()' идет куда-то другим. – Duncan

1
super().__init__(*args, **kwargs) 

Понятно, что вы не проходите «я» - оно вставлено автоматически.

super() был первым разработан в Python 2, чтобы классы для повторного использования в качестве Mixins в иерархии классов таким образом, что их непосредственный суперкласс может измениться:

Давайте supose в какой-то момент времени, ваш код, как:

class A: pass 
class B(A): 
    def __init__(self, *args, **kwargs): 
      ... 
      # Fixed call to A 
      A.__init__(self, *args, **kwargs) 

class C(A): 
    def __init__(self, *args, **kwargs): 
      ... 
      # Fixed call to A 
      A.__init__(self, *args, **kwargs) 

class D(C, B): 
    pass 

на данный момент, правильный код ООП должен выполнить C.__init__, который должен приковать вызов B.__init__: но когда суперкласс имя зашиты, что не бывает - A «s __init__ всегда придет следующий. И если вы жёсткий код B.__init__ в C, вы бы не допустили C от работы без B, победив цель множественного наследования.

При использовании super() вместо Питона выполнить поиск метода для следующего родительского класса смотря на классе __mro__ атрибута (MRO = разрешение метода заказ. __mro__ представляет собой конкретный атрибут прилагается к каждому классу Python). - Итак, если в какой-то момент времени класс D выше не наследуется от B, звонки super().__init__ в C будут автоматически перенаправлены прямо на A.

Следует также отметить, что в Python 3 была введена беззаметная форма super, чтобы облегчить ее использование - до этого нужно было жестко привязать ссылку к собственному классу, а также вставить параметры self. Эта форма является одним из немногих исключений в Python, которые жестко закодированы в самом компиляторе - они меняют вещи внутри методов, когда super (или __class__) отображается внутри тела метода (а именно, он создает переменную __class__, указывающую на сам класс который использует вызов super)

Смежные вопросы