¿Cómo inicializo la clase base (super)?

125

En Python, considere que tengo el siguiente código:

>>> 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?

¿Cómo inicializo el SuperClass __init__en la subclase? Estoy siguiendo el tutorial de Python y no cubre eso. Cuando busqué en Google, encontré más de una forma de hacerlo. ¿Cuál es la forma estándar de manejar esto?

Jeremy
fuente

Respuestas:

146

Python (hasta la versión 3) admite clases de "estilo antiguo" y de estilo nuevo. Las clases de estilo nuevo se derivan objecty son lo que está utilizando, e invocan su clase base, por super()ejemplo,

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)

Debido a que Python conoce las clases de estilo antiguo y nuevo, existen diferentes formas de invocar un método base, por lo que ha encontrado múltiples formas de hacerlo.

En aras de la integridad, las clases de estilo antiguo llaman a los métodos base explícitamente utilizando la clase base, es decir

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

Pero como ya no deberías usar el estilo antiguo, no me importaría demasiado esto.

Python 3 solo conoce las clases de estilo nuevo (no importa si deriva objecto no).

Ivo van der Wijk
fuente
37

Ambos

SuperClass.__init__(self, x)

o

super(SubClass,self).__init__( x )

funcionará (prefiero el segundo, ya que se adhiere más al principio DRY).

Ver aquí: http://docs.python.org/reference/datamodel.html#basic-customization

adamk
fuente
8
incorrecto. super solo funciona con clases de estilo nuevo, y es la única forma adecuada de llamar a una base cuando se usan clases de estilo nuevo. Además, también debe pasar 'self' explícitamente usando la construcción de estilo antiguo.
Ivo van der Wijk
1
@Ivo: el OP dio una clase de estilo nuevo en el ejemplo, y no tiene mucho sentido hablar de la diferencia entre estilo nuevo y estilo antiguo, ya que ya nadie debería usar el estilo antiguo. El enlace que le di (a los documentos de Python) sugiere que hay más de una forma "adecuada" de llamar a la superclase __init__.
adamk
21

¿Cómo inicializo la clase base (super)?

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

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

Use un superobjeto para asegurarse de obtener el siguiente método (como método enlazado) en el orden de resolución del método. En Python 2, debe pasar el nombre de la clase y selfsuper para buscar el __init__método enlazado :

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

En Python 3, hay un poco de magia que hace superinnecesarios los argumentos , y como beneficio adicional funciona un poco más rápido:

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

Codificar al padre de la siguiente manera evita que use la herencia múltiple cooperativa:

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

Tenga en cuenta que __init__solo puede regresarNone : está destinado a modificar el objeto en el lugar.

Alguna cosa __new__

Hay otra forma de inicializar instancias, y es la única forma de subclases de tipos inmutables en Python. Por lo que es necesario si desea subclase stro tupleu otro objeto inmutable.

Puede pensar que es un método de clase porque obtiene un argumento de clase implícito. Pero en realidad es un método estático . Así que hay que llamar __new__con clsforma explícita.

Por lo general, devolvemos la instancia __new__, por lo que si lo hace, también debe llamar a su base a __new__través superde su clase base. Entonces, si usa ambos métodos:

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 esquiva un poco la rareza de las súper llamadas causadas por __new__ser un método estático, pero aún debe pasar clsal __new__método no vinculado :

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')
Aaron Hall
fuente