Comment initialiser la (super) classe de base?

126

En Python, considérez que j'ai le code suivant:

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

Comment initialiser le SuperClass __init__dans la sous-classe? Je suis le tutoriel Python et cela ne couvre pas cela. Lorsque j'ai cherché sur Google, j'ai trouvé plus d'une façon de faire. Quelle est la manière standard de gérer cela?

Jérémie
la source

Réponses:

147

Python (jusqu'à la version 3) supporte les classes «ancien style» et nouveau style. Les classes de nouveau style sont dérivées de objectet sont ce que vous utilisez, et invoquent leur classe de base par super()exemple

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)

Parce que python connaît les classes de style ancien et nouveau, il existe différentes façons d'appeler une méthode de base, c'est pourquoi vous avez trouvé plusieurs façons de le faire.

Par souci d'exhaustivité, les classes à l'ancienne appellent les méthodes de base explicitement en utilisant la classe de base, ie

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

Mais comme vous ne devriez plus utiliser le style ancien, je ne m'en soucierais pas trop.

Python 3 ne connaît que les classes de nouveau style (peu importe si vous en dérivez objectou non).

Ivo van der Wijk
la source
38

Tous les deux

SuperClass.__init__(self, x)

ou

super(SubClass,self).__init__( x )

fonctionnera (je préfère le 2ème, car il adhère davantage au principe DRY).

Voir ici: http://docs.python.org/reference/datamodel.html#basic-customization

Adamk
la source
8
faux. super ne fonctionne qu'avec des classes de nouveau style, et c'est la seule façon correcte d'appeler une base lors de l'utilisation de classes de nouveau style. De plus, vous devez également transmettre explicitement «self» en utilisant la construction à l'ancienne.
Ivo van der Wijk le
1
@Ivo - l'OP a donné une nouvelle classe de style dans l'exemple, et il est inutile de parler de la différence entre le nouveau et l'ancien, car personne ne devrait plus utiliser l'ancien. Le lien que j'ai donné (vers la documentation Python) suggère qu'il y a plus d'une manière «correcte» d'appeler la super-classe __init__.
adamk
21

Comment initialiser la (super) classe de base?

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

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

Utilisez un superobjet pour vous assurer d'obtenir la méthode suivante (en tant que méthode liée) dans l'ordre de résolution de la méthode. Dans Python 2, vous devez passer le nom de la classe et selfà super pour rechercher la __init__méthode liée :

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

Dans Python 3, il y a un peu de magie qui rend les arguments superinutiles - et comme avantage secondaire, cela fonctionne un peu plus vite:

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

Le codage en dur du parent comme celui-ci ci-dessous vous empêche d'utiliser l'héritage multiple coopératif:

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

Notez que __init__peut uniquement renvoyerNone - il est destiné à modifier l'objet sur place.

Quelque chose __new__

Il existe un autre moyen d'initialiser les instances - et c'est le seul moyen pour les sous-classes de types immuables en Python. Il est donc nécessaire si vous souhaitez sous str- classer ou tupleou un autre objet immuable.

Vous pourriez penser que c'est une méthode de classe car elle obtient un argument de classe implicite. Mais c'est en fait une méthode statique . Donc , vous devez appeler __new__avec clsexplicitement.

Nous renvoyons généralement l'instance à partir de __new__, donc si vous le faites, vous devez également appeler votre base __new__via superégalement dans votre classe de base. Donc, si vous utilisez les deux méthodes:

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 évite un peu la bizarrerie des super appels causés par le fait d' __new__être une méthode statique, mais vous devez toujours passer clsà la __new__méthode non liée :

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')
Salle Aaron
la source