Wie initialisiere ich die Basisklasse (Superklasse)?

125

Bedenken Sie, dass ich in Python den folgenden Code habe:

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

Wie initialisiere ich das SuperClass __init__in der Unterklasse? Ich folge dem Python-Tutorial und es behandelt das nicht. Bei der Suche bei Google habe ich mehr als eine Möglichkeit gefunden. Was ist die Standardmethode, um damit umzugehen?

Jeremy
quelle

Antworten:

146

Python (bis Version 3) unterstützt Klassen im "alten" und neuen Stil. Klassen neuen Stils werden von dem abgeleitet, objectwas Sie verwenden, und rufen ihre Basisklasse über super()z

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)

Da Python sich mit Klassen im alten und neuen Stil auskennt, gibt es verschiedene Möglichkeiten, eine Basismethode aufzurufen. Aus diesem Grund haben Sie mehrere Möglichkeiten gefunden, dies zu tun.

Der Vollständigkeit halber rufen Klassen alten Stils Basismethoden explizit unter Verwendung der Basisklasse auf, d. H.

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

Aber da Sie keinen alten Stil mehr verwenden sollten, würde mich das nicht allzu sehr interessieren.

Python 3 kennt nur Klassen neuen Stils (unabhängig davon, ob Sie davon abgeleitet sind objectoder nicht).

Ivo van der Wijk
quelle
37

Beide

SuperClass.__init__(self, x)

oder

super(SubClass,self).__init__( x )

wird funktionieren (ich bevorzuge die 2., da sie mehr dem DRY-Prinzip entspricht).

Siehe hier: http://docs.python.org/reference/datamodel.html#basic-customization

Adamk
quelle
8
falsch. super funktioniert nur mit Klassen neuen Stils und ist die einzig richtige Möglichkeit, eine Basis aufzurufen, wenn Klassen neuen Stils verwendet werden. Darüber hinaus müssen Sie 'self' explizit mit dem Konstrukt alten Stils übergeben.
Ivo van der Wijk
1
@Ivo - Das OP hat im Beispiel eine Klasse im neuen Stil angegeben, und es macht wenig Sinn, über den Unterschied zwischen neuem und altem Stil zu sprechen, da niemand mehr den alten Stil verwenden sollte. Der Link, den ich (zu den Python-Dokumenten) gegeben habe, deutet darauf hin, dass es mehr als einen "richtigen" Weg gibt, die Superklasse aufzurufen __init__.
Adamk
21

Wie initialisiere ich die Basisklasse (Superklasse)?

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

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

Verwenden Sie ein superObjekt, um sicherzustellen, dass Sie die nächste Methode (als gebundene Methode) in der Reihenfolge der Methodenauflösung erhalten. In Python 2 müssen Sie den Klassennamen übergeben und selfsuper, um die gebundene __init__Methode nachzuschlagen :

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

In Python 3 gibt es ein wenig Magie, die die Argumente superunnötig macht - und als Nebeneffekt funktioniert es etwas schneller:

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

Wenn Sie das übergeordnete Element wie folgt fest codieren, können Sie keine kooperative Mehrfachvererbung verwenden:

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

Beachten Sie, dass __init__möglicherweise nur zurückgegeben wirdNone - es ist beabsichtigt, das Objekt an Ort und Stelle zu ändern.

etwas __new__

Es gibt eine andere Möglichkeit, Instanzen zu initialisieren - und dies ist die einzige Möglichkeit für Unterklassen unveränderlicher Typen in Python. So ist es erforderlich , wenn Sie zu Unterklasse wollen stroder tupleoder ein anderes unveränderliches Objekt.

Sie könnten denken, es ist eine Klassenmethode, weil sie ein implizites Klassenargument erhält. Aber es ist eigentlich eine statische Methode . Sie müssen also rufen __new__mit clsexplizit.

Wir kehren in der Regel die Instanz aus __new__, so dass , wenn Sie dies tun, müssen Sie auch Ihre Basis ist nennen __new__über superals auch in Ihrer Basisklasse. Wenn Sie also beide Methoden verwenden:

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 umgeht ein wenig die Verrücktheit der Superaufrufe, die durch __new__eine statische Methode verursacht werden, aber Sie müssen trotzdem clsan die nicht gebundene __new__Methode übergeben:

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
quelle