Как вызвать супер конструктор в Python?

class A:
    def __init__(self):
        print("world")

class B(A):
    def __init__(self):
       print("hello")

B()  # output: hello

Во всех других языках, с которыми я работал, супер-конструктор вызывается неявно. Как можно вызвать его в Python? Я ожидал бы super(self) но это не работает.

Ответ 1

super() возвращает родительский объект в классах нового стиля:

class A(object):
    def __init__(self):
        print "world"

class B(A):
    def __init__(self):
        print "hello"
        super(B, self).__init__()

B()

Ответ 2

В соответствии с другими ответами существует множество способов вызова методов суперкласса (включая конструктор), однако в Python-3.x процесс упрощен:

Python-2.x

class A(object):
 def __init__(self):
   print "world"

class B(A):
 def __init__(self):
   print "hello"
   super(B, self).__init__()

Python-3.x

class A(object):
 def __init__(self):
   print("world")

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

super() теперь эквивалентен super(<containing classname>, self) в соответствии с документами.

Ответ 3

С классами старого стиля Python 2.x это будет следующим:

class A: 
 def __init__(self): 
   print "world" 

class B(A): 
 def __init__(self): 
   print "hello" 
   A.__init__(self)

Ответ 4

Один из способов - вызвать конструктор A и передать self в качестве аргумента, например так:

class B(A):
    def __init__(self):
        A.__init__(self)
        print "hello"

Преимущество этого стиля в том, что он очень понятен. Это называется инициализатором. Недостатком является то, что он не очень хорошо обрабатывает наследование в форме ромба, так как в итоге вы можете дважды вызвать инициализатор общего базового класса.

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

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

Ответ 5

Короткий ответ

super(DerivedClass, self).__init__()

Длинный ответ

Что делает super()?

Он принимает указанное имя класса, находит его базовые классы (Python допускает множественное наследование) и ищет метод (в данном случае __init__) в каждом из них слева направо. Как только он находит метод доступным, он вызывает его и завершает поиск.

Как мне вызвать init всех базовых классов?

Выше работает, если у вас есть только один базовый класс. Но Python допускает множественное наследование, и вы можете убедиться, что все базовые классы инициализированы правильно. Для этого у вас должен быть каждый вызов базового класса init:

class Base1:
  def __init__():
    super(Base1, self).__init__()

class Base2:
  def __init__():
    super(Base2, self).__init__()

class Derived(Base1, Base2):
  def __init__():
    super(Derived, self).__init__()

Что если я забуду вызвать init для супер?

Конструктор (__new__) вызывается в цепочке (как в C++ и Java). После создания экземпляра вызывается только этот инициализатор экземпляра (__init__) без какой-либо неявной цепочки для его суперкласса.

Ответ 6

Просто добавьте пример с параметрами:

class B(A):
    def __init__(self, x, y, z):
        A.__init__(self, x, y)

Учитывая производный класс B, который требует определения переменных x, y, z, и суперкласс A, который требует определения x, y, вы можете вызвать статический метод init суперкласса A со ссылкой на текущий экземпляр подкласса (self) и затем списком ожидаемых аргументов.

Ответ 7

Я использую следующую формулу, которая расширяет предыдущие ответы:

class A(object):
 def __init__(self):
   print "world"

class B(A):
 def __init__(self):
   print "hello"
   super(self.__class__, self).__init__()

B()

Таким образом, вам не нужно повторять имя класса в вызове super. Это может пригодиться, если вы кодируете большое количество классов и хотите сделать свой код в методах инициализатора независимым от имени класса.