Detaillierte Erläuterung der Python-Vererbung und der Methodenauflösungsreihenfolge (MRO) | Beispiele und Verwendung der Funktion super()

erben

Vererbung ist ein wichtiges Konzept in der objektorientierten Programmierung. Durch Vererbung können wir einer Klasse ermöglichen, Eigenschaften und Methoden in anderen Klassen zu erhalten, das Schreiben von sich wiederholendem Code vermeiden und das Open and Closed Principle (OCP) einhalten. Vererbung ist eine gängige Methode zur Erweiterung einer Klasse.

Definieren Sie eine Klasse „Tier“.

Wir definieren zunächst eine Klasse Animal, die über zwei Methoden run() und sleep() verfügt, was angibt, dass das Tier laufen und schlafen kann.

class Animal:
    def run(self):
        print('动物会跑~~~')

    def sleep(self):
        print('动物睡觉~~~')

Definieren Sie eine Klasse Hund

Nun wollen wir eine Klasse Hund definieren, die nicht nur laufen und schlafen, sondern auch bellen kann. Wir können die Animal-Klasse direkt ändern und die bark()-Methode hinzufügen, aber dies verstößt gegen die OCP-Prinzipien. Ein besserer Weg ist die Vererbung .

class Dog(Animal):
    def bark(self):
        print('汪汪汪~~~') 

    def run(self):
        print('狗跑~~~~')   

Im obigen Code geben wir class Dog(Animal):an, dass die Dog-Klasse von der Animal-Klasse erbt. Auf diese Weise kann die Dog-Klasse direkt die Eigenschaften und Methoden der Animal-Klasse abrufen. Wir können auch Methoden in der Animal-Klasse überschreiben, beispielsweise die run()-Methode in der Dog-Klasse neu definieren.

Erstellen Sie Objekte und rufen Sie Methoden auf

Jetzt können wir ein Objekt der Dog-Klasse erstellen d = Dog()und seine Methoden wie d.run(), d.sleep()und aufrufen d.bark().

d = Dog()
d.run()  # 输出:狗跑~~~~
d.sleep()  # 输出:动物睡觉~~~
d.bark()  # 输出:汪汪汪~~~

Beziehung zwischen Klassen

Mithilfe der Vererbung können wir hierarchische Beziehungen zwischen Klassen herstellen. Wenn beim Erstellen einer Klasse die übergeordnete Klasse weggelassen wird, ist die standardmäßige übergeordnete Klasse object. objectIst die übergeordnete Klasse aller Klassen, daher erben alle Klassen von object.

class Person(object):
    pass

Mit Funktionen wie return und return können wir issubclass()überprüfen, ob eine Klasse eine Unterklasse einer anderen Klasse ist .issubclass(Animal, Dog)Falseissubclass(Animal, object)True

Wir können isinstance()die Funktion auch verwenden, um zu prüfen, ob ein Objekt eine Instanz einer Klasse ist. Wenn diese Klasse die übergeordnete Klasse dieses Objekts ist, wird sie ebenfalls zurückgegeben True. Alle Objekte sind objectInstanzen von .

print(isinstance(d, Dog))  # 输出:True
print(isinstance(d, Animal))  # 输出:True
print(isinstance(d, object))  # 输出:True
print(isinstance(print, object))  # 输出:True

Durch Vererbung wird die Beziehung zwischen Klassen klarer und die Wiederverwendung und Erweiterung von Code erleichtert.

Mehrfachvererbung

Neben der Einzelvererbung unterstützt Python auch die Mehrfachvererbung, d. h. eine Unterklasse kann Eigenschaften und Methoden von mehreren übergeordneten Klassen erben. Dies bietet uns mehr Flexibilität und erleichtert die Organisation und Wiederverwendung von Code.

Definieren Sie eine Hashiqi-Klasse

Angenommen, wir haben auch eine Klasse Hashiqi, die eine besondere Art von Hund darstellt. Zusätzlich zum Grundverhalten eines Hundes verfügt sie auch über eine eigene einzigartige Methode fan_sha(), die einen dummen Husky darstellt.

class Hashiqi(Dog):
    def fan_sha(self):
        print('我是一只傻傻的哈士奇')

Im obigen Code definieren wir eine Hashiqi-Klasse, die von der Dog-Klasse erbt. Daher kann die Hashiqi-Klasse nicht nur die Eigenschaften und Methoden der Tier- und Hundeklassen haben, sondern verfügt auch über ihre eigene einzigartige fan_sha()-Methode.

Erstellen Sie Objekte und rufen Sie Methoden auf

Jetzt können wir Objekte der Hashiqi-Klasse erstellen und h = Hashiqi()ihre Methoden wie h.run(), und aufrufen .h.sleep()h.bark()h.fan_sha()

h = Hashiqi()
h.run()  # 输出:狗跑~~~~
h.sleep()  # 输出:动物睡觉~~~
h.bark()  # 输出:汪汪汪~~~
h.fan_sha()  # 输出:我是一只傻傻的哈士奇

Durch Mehrfachvererbung können wir flexiblere und komplexere Beziehungsklassenstrukturen erreichen. Beim Erstellen einer Unterklasse müssen Sie nur mehrere übergeordnete Klassen angeben, und die Unterklasse kann die Eigenschaften und Methoden aller übergeordneten Klassen direkt abrufen, wodurch die Coderedundanz verringert wird.

Vererbung ist eines der wichtigen Merkmale der objektorientierten Programmierung: Sie kann die Lesbarkeit, Wartbarkeit und Skalierbarkeit von Code verbessern und das Öffnungs- und Schließprinzip einhalten. Beim Entwerfen von Klassen sollten wir Vererbungsbeziehungen vollständig berücksichtigen und gute Code-Organisations- und Designprinzipien befolgen.

Wenn eine Klasse von mehreren übergeordneten Klassen erbt, kann es zu Namenskonflikten kommen. Wenn beispielsweise zwei übergeordnete Klassen eine Methode oder Eigenschaft mit demselben Namen haben, kommt es beim Aufruf dieses Namens in der untergeordneten Klasse zu Mehrdeutigkeiten. Um dieses Problem zu lösen, bietet Python Method Resolution Order (kurz MRO) an.

Method Resolution Order (MRO)

In Python hat jede Klasse eine Methodenauflösungsreihenfolge. Dies ist die Reihenfolge, in der die übergeordneten Klassen, von denen sie erbt, durchsucht werden. 类名.__mro__Sie können oder verwenden, 类名.mro()um die Reihenfolge der Methodenauflösung anzuzeigen. Nachfolgend finden Sie ein Beispiel:

class A:
    def method(self):
        print("A")

class B(A):
    def method(self):
        print("B")

class C(A):
    def method(self):
        print("C")

class D(B, C):
    pass

print(D.__mro__)
print(D.mro())

Wenn Sie den obigen Code ausführen, werden die folgenden Ergebnisse ausgegeben:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

Wie aus den Ausgabeergebnissen ersichtlich ist, lautet die Reihenfolge der Methodenauflösung D -> B -> C -> A -> Objekt. Das heißt, wenn eine Methode für eine Instanz der Klasse D aufgerufen wird method(), wird sie in dieser Reihenfolge durchsucht und die erste passende Methode wird ausgeführt.

super()-Funktion

Die Funktion super() ist eine Möglichkeit, eine Methode einer übergeordneten Klasse aufzurufen. Sie können super().方法名()das Formular verwenden, um Methoden der übergeordneten Klasse aufzurufen, ohne den Namen der übergeordneten Klasse explizit anzugeben. Zum Beispiel:

class A:
    def method(self):
        print("A")

class B(A):
    def method(self):
        super().method()
        print("B")

b = B()
b.method()

Die Ausgabe ist:

A
B

Im obigen Code erbt Klasse B von Klasse A und verwendet super().method() in ihrer eigenen method()-Methode, um die method()-Methode in der übergeordneten Klasse A aufzurufen, und gibt dann „B“ aus.

Durch die Verwendung der Funktion super() kann sichergestellt werden, dass die Methoden der übergeordneten Klasse bei der Mehrfachvererbung nacheinander in der Reihenfolge der Methodenauflösung aufgerufen werden, wodurch Namenskonflikte und Mehrdeutigkeiten vermieden werden.

Wenn bei der Mehrfachvererbung eine Diamantvererbung vorliegt, verwendet Python den C3-Linearisierungsalgorithmus, um die Methodenauflösungsreihenfolge (MRO) zu bestimmen, um wiederholte Methodenaufrufe und redundanten Code zu vermeiden.

C3-Linearisierungsalgorithmus

Der C3-Linearisierungsalgorithmus generiert eine Linearisierungsliste, die die folgenden Bedingungen erfüllt, indem er die Linearisierungsreihenfolgen mehrerer übergeordneter Klassen zusammenführt:

  1. Unterklassen gehen immer übergeordneten Klassen voraus.
  2. Wenn eine Klasse früher in der Liste angezeigt wird, werden auch alle ihre übergeordneten Klassen früher angezeigt.
  3. Wenn einer Klasse mehrere übergeordnete Klassen folgen, bleibt ihre Reihenfolge unverändert.

Auf diese Weise wird in der Methodenauflösungssequenz die Methode jeder Klasse nur einmal aufgerufen, wodurch wiederholte Aufrufe und redundanter Code vermieden werden.

Beispiel

Hier ist ein Beispiel für die Vererbung von Diamanten:

class A:
    def method(self):
        print("A")

class B(A):
    pass

class C(A):
    def method(self):
        print("C")

class D(B, C):
    pass

d = D()
d.method()

Im obigen Code erbt die Klasse D von B und C, und sowohl B als auch C erben von A. Wenn wir eine Instanz von D erstellen und die Methode aufrufen method(), lautet die gemäß dem C3-Linearisierungsalgorithmus erhaltene Methodenauflösungsreihenfolge D -> B -> C -> A, sodass das Ausgabeergebnis „C“ ist.

super()-Funktion und Diamantvererbung

Bei Verwendung der Funktion super() ruft Python die Methoden der übergeordneten Klasse gemäß der von MRO festgelegten Reihenfolge der Methodenauflösung auf. Bei der Diamantvererbung ruft die Funktion super() die Methoden jeder übergeordneten Klasse nacheinander in der MRO-Reihenfolge auf und stellt sicher, dass jede Methode nur einmal aufgerufen wird.

class A:
    def method(self):
        print("A")

class B(A):
    def method(self):
        super().method()
        print("B")

class C(A):
    def method(self):
        super().method()
        print("C")

class D(B, C):
    pass

d = D()
d.method()

Wenn Sie den obigen Code ausführen, lautet die Ausgabe:

A
C
B

In diesem Beispiel lautet die Methodenauflösungsreihenfolge der Klasse D D -> B -> C -> A. Wenn die Methode aufgerufen wird d.method(), ruft super().method() nacheinander die method()-Methoden der Klassen B, C und A auf. Durch MRO wird jede Klassenmethode nur einmal aufgerufen, wodurch wiederholte Aufrufe und redundanter Code vermieden werden.

Klassische und neue Stile

In Python 2.x-Versionen gibt es das Konzept klassischer Klassen und Klassen neuen Stils. Klassische Klassen sind Klassen, die nicht explizit vom Objekt erben, während Klassen im neuen Stil Klassen sind, die explizit vom Objekt erben.

In klassischen Klassen verwendet Python eine Tiefensuchmethode, um die Reihenfolge der Methodenaufrufe aufzulösen. Bei dieser Methode gibt es einige Probleme, z. B. wiederholte Methodenaufrufe und die Unfähigkeit, die Reihenfolge der Methodenauflösung zu implementieren, wenn Mehrfachvererbung implementiert ist.

In Klassen neuen Stils verwendet Python den C3-Linearisierungsalgorithmus, um die Reihenfolge der Methodenaufrufe aufzulösen. Diese Methode kann sicherstellen, dass die Methode nur einmal aufgerufen wird, und löst das Problem der unsicheren Reihenfolge der Methodenauflösung bei Mehrfachvererbung.

Um eine bessere Kompatibilität mit alten und neuen Versionen von Python zu gewährleisten, wurde in Python 2.3 eine spezielle Syntax eingeführt, die beim Definieren von Klassen verwendet wird, wodurch alle Klassen als Klassen neuen class ClassName(object):Stils definiert werden.

In der Python 3.x-Version sind alle Klassen standardmäßig als Klassen neuen Stils definiert und es besteht keine Notwendigkeit, explizit vom Objekt zu erben.

Zusammenfassen

Die Mehrfachvererbung in Python bietet Programmierern flexiblere Designoptionen, bringt jedoch auch einige Herausforderungen mit sich. Um Namenskonflikte und Mehrdeutigkeiten zu vermeiden, muss die Methodenauflösungsreihenfolge (MRO) bei der Mehrfachvererbung korrekt festgelegt werden, um die Korrektheit und Effizienz von Methodenaufrufen sicherzustellen.

Python3.x hat alle Klassen standardmäßig als Klassen neuen Stils definiert und verwendet den C3-Linearisierungsalgorithmus, um das Problem der Mehrfachvererbung zu lösen. Es besteht keine Notwendigkeit, der Einstellung von MRO besondere Aufmerksamkeit zu schenken.

In Python bedeutet Rautenvererbung, dass eine Unterklasse gleichzeitig von zwei Klassen mit einer gemeinsamen Elternklasse erbt und so eine rautenförmige Vererbungsstruktur bildet. Diese Vererbungsstruktur kann Probleme wie wiederholte Methodenaufrufe und redundanten Code verursachen.

Um die durch die Diamantvererbung verursachten Probleme zu lösen, verwendet Python den C3-Linearisierungsalgorithmus, um die Reihenfolge der Methodenauflösung (Method Resolution Order, MRO) zu bestimmen. Konkrete Schritte sind wie folgt:

  1. Generieren Sie eine topologisch sortierte Liste (DAG) entsprechend der Deklarationsreihenfolge der Klassen.
  2. In einer topologisch sortierten Liste wird die Elternliste jedes Knotens überprüft und die Position seines Elternknotens vor sich selbst verschoben. Auf diese Weise wird garantiert, dass die Unterklasse vor der Elternklasse steht.
  3. Für den Fall, dass mehrere übergeordnete Klassen gleichzeitig nach demselben Knoten erscheinen, muss ihre Reihenfolge in der Basisklassenliste unverändert bleiben.

Durch die Verwendung des C3-Linearisierungsalgorithmus kann Python die Probleme wiederholter Methodenaufrufe und redundanten Codes vermeiden. Darüber hinaus berechnet Python den MRO während der Klassendefinition automatisch und speichert ihn in speziellen Attributen, __mro__damit Entwickler ihn anzeigen können.

Es ist zu beachten, dass bei der tatsächlichen Verwendung bei Diamantvererbung super()Probleme vermieden werden können, indem die Vererbungsbeziehung der Klasse richtig gestaltet und Funktionen verwendet werden. Durch den sinnvollen Einsatz von Polymorphismus, Zusammensetzung und anderen Technologien kann auch die durch Vererbung verursachte Komplexität verringert werden.

Empfohlene Python-Boutique-Kolumnen


Grundkenntnisse in Python (0 grundlegende Einführung)

[Python-Grundkenntnisse] 0.print()-Funktion
[Python-Grundkenntnisse] 1. Datentypen, Datenanwendungen, Datenkonvertierung
[Python-Grundkenntnisse] 2. Wenn bedingte Beurteilung und Bedingungsverschachtelung
[Python-Grundkenntnisse] 3.input() Funktionen
[Grundkenntnisse in Python] 4. Listen und Wörterbücher
[Grundkenntnisse in Python] 5. For-Schleifen und While-Schleifen
[Grundkenntnisse in Python] 6. Boolesche Werte und vier Arten von Anweisungen (break, continue, pass, else)
[Grundkenntnisse in Python] 7. Praktische Bedienung – Verwenden Sie Python, um das Spiel „Word PK“ zu implementieren (1)
[Python-Grundlagen] 7. Praktische Bedienung – Verwenden Sie Python, um das Spiel „Word PK“ zu implementieren (2)
[Python-Grundlagen] 8. Programmierdenken: So lösen Sie Probleme – Denkkapitel
[Grundkenntnisse in Python] 9. Definition und Aufruf von Funktionen
[Grundkenntnisse in Python] 10. Programme mit Funktionen schreiben – Praktisches Kapitel
[Grundkenntnisse in Python] 10. Verwendung von Python um das Stein-Schere-Papier-Spiel zu implementieren - Funktionsübungs-Operations-Kapitel
[Python-Grundlagen] 11. So debuggen Sie - Häufige Fehlerursachen und Ideen zur Fehlerbehebung - Denkkapitel
[Python-Grundlagen] 12. Klassen und Objekte (1)
[Python-Grundlagen] 12 . Klassen und Objekte (2)
[Python-Grundlagen] Wissen] 13. Klassen und Objekte (3)
[Grundkenntnisse über Python] 13. Klassen und Objekte (4)
[Grundkenntnisse über Python] 14. Aufbau eines Bibliotheksverwaltungssystems (praktisch). Betrieb von Klassen und Objekten)
[Grundkenntnisse in Python] 15. Grundkenntnisse im Programmieren
[Grundkenntnisse von Python] 16. Grundlagen des Lesens und Schreibens von Dateien sowie von Operationen
[Grundkenntnisse von Python] 16. Python-Implementierung von „Fragen zum Diktieren alter Gedichte“ (Lesen, Schreiben und Codieren von Dateien – praktischer Betrieb)
[Grundkenntnisse von Python] 17. Das Modulkonzept und die Einführung
[Python-Grundlagen] 18. Praktische Bedienung – Verwendung von Python zum automatischen Versenden von Massen-E-Mails
[Python-Grundlagen] 19. Produktdenken und Verwendung von Flussdiagrammen – Denken
[Python-Grundlagen] 20. Python-Implementierung „Was man zum Mittagessen essen soll“ (Produktdenken – Praktische Bedienung)
[Grundkenntnisse in Python] 21. Der richtige Weg, effizient und langsam zu öffnen – Abschluss
[Python-Dateiverarbeitung] Lesen, Verarbeiten und Schreiben von CSV-Dateien
[Python-Dateiverarbeitung ] Automatische Excel-Verarbeitung (mit openpyxl)
[Python-Dateiverarbeitung] - Excel-Formatverarbeitung


Python-Crawler-Kenntnisse

[Python-Crawler] 1. Grundkenntnisse über Crawler
[Python-Crawler] 2. Grundkenntnisse über Webseiten
[Python-Crawler] 3. Erste Erfahrungen mit Crawlern (BeautifulSoup-Analyse)
[Python-Crawler] 4. Praktischer Crawler-Betrieb (Dish-Crawling)
[Python Crawler] 5. Praktischer Crawler-Betrieb (Crawling-Texte)
[Python-Crawler] 6. Praktischer Crawler-Betrieb (Daten mit Parametern anfordern)
[Python-Crawler] 7. Wo werden die gecrawlten Daten gespeichert? [Python - Crawler] 8. Sehen Sie sich die Vergangenheit an
und lernen Sie das Neue kennen Melden Sie sich rechtzeitig bei Ihnen [Python-Crawler] 12. Bauen Sie Ihre Crawler-Armee auf [Python-Crawler] 13. Was Sie essen können, ohne dick zu werden (praktische Crawler-Übung) [Python-Crawler] 14. Erklärung des Scrapy-Frameworks [Python-Crawler] 15. Praxis des Scrapy-Frameworks (Beliebter Job-Crawler Take) [Python-Crawler] 16. Zusammenfassung und Überprüfung der Crawler-Wissenspunkte







Supongo que te gusta

Origin blog.csdn.net/qq_41308872/article/details/132852073
Recomendado
Clasificación