2014-02-07 4 views
13

В Python 2.7 и 3, я использую следующий метод для вызова функции суперкласса:разница между супер() и вызывающим суперкласса непосредственно

class C(B): 
    def __init__(self): 
     B.__init__(self) 

Я вижу это также можно заменить B.__init__(self) с super(B, self).__init__() и python3 super().__init__().

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

ответ

24

Для одиночного наследования super() - это просто более удобный способ обратиться к базовому типу. Таким образом, вы делаете код более удобным для обслуживания, например, если вы хотите изменить имя базового типа. Когда вы используете super везде, вам просто нужно его изменить в строке class.

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

Это, по существу, позволяет типам иметь свойство алмаза, например. у вас есть один базовый тип A и два типа: B и C, которые оба получены от A. И тогда у вас есть тип E, который наследует как от B, так и от C (что делает его неявным наследованием от A слишком-дважды). Если вы вызовете методы базовых типов прямо сейчас, вы в конечном итоге вызовете метод A дважды. Но использование super, это будет вызывать только один раз:

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

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

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

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

Когда мы теперь экземпляр D, мы получаем следующий результат:

>>> D() 
A 
B 
C 
D 
<__main__.D object at 0x000000000371DD30> 

Теперь, давайте делать все, что снова вручную вызова базового типа метод:

class A2 (object): 
    def __init__ (self): 
     print('A2') 

class B2 (A2): 
    def __init__ (self): 
     A2.__init__(self) 
     print('B2') 

class C2 (A2): 
    def __init__ (self): 
     A2.__init__(self) 
     print('C2') 

class D2 (C2, B2): 
    def __init__ (self): 
     B2.__init__(self) 
     C2.__init__(self) 
     print('D2') 

И это выход:

>>> D2() 
A2 
B2 
A2 
C2 
D2 
<__main__.D2 object at 0x0000000003734E48> 

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

+1

базовый тип:?. базовый класс, класс child и т. д. :) кажется более естественным –

+0

Очень ясный пример, кстати, спасибо :) @poke –

2

Не могли бы вы пояснить, почему мы печатаем super().__init__() внутри основного класса A? Похоже, что он отлично работает без этой линии.

+0

Я пришел к пониманию, что это необходимо для случая, когда этот класс А имеет соседний класс на том же уровне. –

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