Python: Super, das weißt du nicht

高洛峰
Freigeben: 2016-11-15 15:14:37
Original
1160 Leute haben es durchsucht

Einführung in die Verwendung von super()

Wenn bei der Klassenvererbung eine Methode neu definiert wird, überschreibt die Methode die gleichnamige Methode der übergeordneten Klasse, aber manchmal hoffen wir, die Funktionen von zu realisieren gleichzeitig die übergeordnete Klasse. Zu diesem Zeitpunkt müssen wir die Methode der übergeordneten Klasse aufrufen, was durch die Verwendung von super erreicht werden kann, wie zum Beispiel:

class Animal(object):
    def __init__(self, name):
        self.name = name
    def greet(self):
        print 'Hello, I am %s.' % self.name

class Dog(Animal):
    def greet(self):
        super(Dog, self).greet()   # Python3 可使用 super().greet()
        print 'WangWang...'
Nach dem Login kopieren

Im Obigen ist Animal das Die übergeordnete Klasse Dog ist die Unterklasse. Wir definieren die Greet-Methode in der Dog-Klasse und rufen gleichzeitig die Methode der übergeordneten Klasse auf :

>>> dog = Dog('dog')
>>> dog.greet()
Hello, I am dog.
WangWang..
Nach dem Login kopieren

Eine der häufigsten Verwendungen von Super kann man als Unterklasse bezeichnen. Rufen Sie die Initialisierungsmethode der übergeordneten Klasse auf, zum Beispiel:

class Base(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

class A(Base):
    def __init__(self, a, b, c):
        super(A, self).__init__(a, b)  # Python3 可使用 super().__init__(a, b)
        self.c = c
Nach dem Login kopieren

Deep into super( )

Nachdem Sie die obige Verwendung gelesen haben, haben Sie möglicherweise das Gefühl, dass die Verwendung von super sehr einfach ist. Es besteht lediglich darin, die übergeordnete Klasse abzurufen und die Methode der übergeordneten Klasse aufzurufen. Tatsächlich ist die von Super erhaltene Klasse im obigen Fall die übergeordnete Klasse, in anderen Fällen ist dies jedoch nicht unbedingt der Fall. Super hat tatsächlich keine wesentliche Beziehung zur übergeordneten Klasse.

Sehen wir uns ein etwas komplizierteres Beispiel mit Mehrfachvererbung an. Der Code lautet wie folgt:

class Base(object):
    def __init__(self):
        print "enter Base"
        print "leave Base"

class A(Base):
    def __init__(self):
        print "enter A"
        super(A, self).__init__()
        print "leave A"

class B(Base):
    def __init__(self):
        print "enter B"
        super(B, self).__init__()
        print "leave B"

class C(A, B):
    def __init__(self):
        print "enter C"
        super(C, self).__init__()
        print "leave C"
Nach dem Login kopieren

Unter diesen ist Base die übergeordnete Klasse, A und B erben von Base. und C erbt von A , B, ihre Vererbungsbeziehung ist wie folgt:

      Base
      /  \
     /    \
    A      B
     \    /
      \  /
       C
Nach dem Login kopieren

Lassen Sie uns nun einen Blick auf die Verwendung werfen:

>>> c = C()
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
Nach dem Login kopieren

Wenn Sie denken, dass Super „ darstellt“ Rufen Sie die Methode der übergeordneten Klasse auf“, dann fragen Sie sich vielleicht, warum der nächste Satz von Enter A nicht Enter Base, sondern Enter B lautet. Der Grund dafür ist, dass Super keine wesentliche Beziehung zur übergeordneten Klasse hat. Lassen Sie uns nun herausfinden, wie Super funktioniert.

MRO-Liste

Tatsächlich berechnet Python für jede von Ihnen definierte Klasse eine MRO-Liste (Method Resolution Order), die die Reihenfolge der Klassenvererbung darstellt. Sie können die folgende Methode verwenden So erhalten Sie die MRO-Liste einer bestimmten Klasse:

>>> C.mro()   # or C.__mro__ or C().__class__.mro()
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
Nach dem Login kopieren

Wie wird die Reihenfolge dieser MRO-Liste ermittelt? Wir werden hier nicht näher darauf eingehen Interessierte Leser können es selbst herausfinden. Im Allgemeinen besteht die MRO-Liste einer Klasse darin, die MRO-Listen aller übergeordneten Klassen zusammenzuführen und die folgenden drei Prinzipien zu befolgen:

Unterklassen stehen immer vor der übergeordneten Klasse

Wenn es mehrere übergeordnete Klassen gibt, werden diese entsprechend ihrer Reihenfolge in der Liste überprüft

Wenn es zwei rechtliche Möglichkeiten für die nächste Klasse gibt, wird die erste übergeordnete Klasse ausgewählt

Super-Prinzip

Super funktioniert wie folgt:

def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls) + 1]
Nach dem Login kopieren

Unter diesen stellt cls die Klasse und inst die Instanz dar. Der obige Code führt zwei Dinge aus:

Get die MRO-Liste von inst

Suchen Sie den Index von cls in der aktuellen MRO-Liste und geben Sie die nächste Klasse zurück, nämlich mro[index 1]

Wenn Sie super (cls, inst) verwenden , sucht Python nach der nächsten Klasse von cls in der MRO-Liste von inst.

Kehren wir nun zum vorherigen Beispiel zurück.

Erster Blick auf die __init__-Methode der Klasse C:

super(C, self).__init__()
Nach dem Login kopieren

Das Selbst hier ist die aktuelle Instanz von C. Das Ergebnis von self.__class__.mro() ist:

[__main__.C, __main__.A, __main__.B, __main__.Base, object]
Nach dem Login kopieren

Wie Sie sehen können, ist die nächste Klasse von C A, also springt sie zum __init__ von A. Zu diesem Zeitpunkt wird A gedruckt und die folgende Codezeile ausgeführt:

super(A, self).__init__()
Nach dem Login kopieren

Beachten Sie, dass self hier auch ist. Für die aktuelle Instanz von C ist die MRO-Liste dieselbe wie oben. Suchen Sie nach der nächsten Klasse von A im MRO und stellen Sie fest, dass es sich um B handelt. Springen Sie also zu __init__ von B. Zu diesem Zeitpunkt wird Enter B anstelle von Enter Base gedruckt.

Der gesamte Prozess ist relativ klar. Der Schlüssel liegt darin, zu verstehen, wie Super funktioniert, und nicht davon auszugehen, dass Super die Methode der übergeordneten Klasse aufruft.

Zusammenfassung

Tatsächlich hat super keine wesentliche Beziehung zur übergeordneten Klasse.

super(cls, inst) ruft die nächste Klasse von cls in der MRO-Liste von inst ab.


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage