Як ініціалізувати базовий (супер) клас?


126

У Python врахуйте, що у мене є такий код:

>>> class SuperClass(object):
    def __init__(self, x):
        self.x = x

>>> class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y
        # how do I initialize the SuperClass __init__ here?

Як мені ініціалізувати SuperClass __init__підклас? Я стежу за підручником Python, і це не охоплює. Під час пошуку в Google я виявив більше, ніж один спосіб. Який стандартний спосіб поводження з цим?

Відповіді:


147

Python (до версії 3) підтримує класи "старого" та "нового стилю". Класи нового стилю походять від того object, що ви використовуєте, і викликайте їх базовий клас super(), наприклад, наприклад

class X(object):
  def __init__(self, x):
    pass

  def doit(self, bar):
    pass

class Y(X):
  def __init__(self):
    super(Y, self).__init__(123)

  def doit(self, foo):
    return super(Y, self).doit(foo)

Оскільки python знає про класи старого та нового стилю, існують різні способи викликати базовий метод, саме тому ви знайшли кілька способів зробити це.

Для повноти класи старого стилю називають базові методи, явно використовуючи базовий клас, тобто

def doit(self, foo):
  return X.doit(self, foo)

Але оскільки ви більше не повинні використовувати старий стиль, я б не переймався цим.

Python 3 знає лише про класи нового стилю (незалежно від того, походите ви objectчи ні).


38

І те й інше

SuperClass.__init__(self, x)

або

super(SubClass,self).__init__( x )

буде працювати (я віддаю перевагу другому, оскільки він більше дотримується принципу DRY).

Дивіться тут: http://docs.python.org/reference/datamodel.html#basic-customization


8
неправильно. super працює лише з класами нового стилю, і це єдиний правильний спосіб викликати базу при використанні класів нового стилю. Крім того, вам також потрібно явно пройти «я», використовуючи конструкцію старого стилю.
Іво ван дер Війк

1
@ Ivo - ОП представив у прикладі клас нового стилю, і мало сенсу говорити про різницю між новим і старим стилем, оскільки ніхто більше не повинен використовувати старий стиль. Посилання, яке я дав (до документів Python), припускає, що існує більше одного "належного" способу виклику суперкласу __init__.
adamk


21

Як ініціалізувати базовий (супер) клас?

class SuperClass(object):
    def __init__(self, x):
        self.x = x

class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y

Використовуйте superоб'єкт, щоб переконатися, що ви отримаєте наступний метод (як зв'язаний метод) у порядку вирішення методу. У Python 2 вам потрібно передати ім'я класу та selfсупер шукати пов'язаний __init__метод:

 class SubClass(SuperClass):
      def __init__(self, y):
          super(SubClass, self).__init__('x')
          self.y = y

У Python 3 є маленька магія, яка робить аргументи superнепотрібними - і, як побічна вигода, вона працює трохи швидше:

 class SubClass(SuperClass):
      def __init__(self, y):
          super().__init__('x')
          self.y = y

Жорстке кодування вищезгаданого батька перешкоджає використанню кооперативного множинного спадкування:

 class SubClass(SuperClass):
      def __init__(self, y):
          SuperClass.__init__(self, 'x') # don't do this
          self.y = y

Зауважте, що __init__може лише повернутисяNone - він призначений для зміни об'єкта на місці.

Щось __new__

Є ще один спосіб ініціалізації екземплярів - і це єдиний спосіб для підкласів незмінних типів у Python. Так що це необхідно , якщо ви хочете підклас strабо tupleабо інший незмінний об'єкт.

Ви можете подумати, що це класний метод, оскільки він отримує неявний аргумент класу. Але це насправді статичний метод . Тож вам потрібно зателефонувати __new__з clsявно.

Ми, як правило, повертаємо екземпляр __new__, тому, якщо ви це зробите, вам також потрібно зателефонувати в базу __new__через superваш базовий клас. Тож якщо ви використовуєте обидва способи:

class SuperClass(object):
    def __new__(cls, x):
        return super(SuperClass, cls).__new__(cls)
    def __init__(self, x):
        self.x = x

class SubClass(object):
    def __new__(cls, y):
        return super(SubClass, cls).__new__(cls)

    def __init__(self, y):
        self.y = y
        super(SubClass, self).__init__('x')

Python 3 ухиляється від дивацтва супервикликів, спричинених __new__статичним методом, але вам все одно потрібно перейти clsдо безмежного __new__методу:

class SuperClass(object):
    def __new__(cls, x):
        return super().__new__(cls)
    def __init__(self, x):
        self.x = x

class SubClass(object):
    def __new__(cls, y):
        return super().__new__(cls)
    def __init__(self, y):
        self.y = y
        super().__init__('x')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.