Vererbung und Polymorphismus

Vererbung und Polymorphismus - dies ist ein sehr wichtiges Konzept in Python. Sie müssen es besser verstehen, wenn Sie lernen wollen.

Erbe

Einer der Hauptvorteile der objektorientierten Programmierung ist die Wiederverwendung. Vererbung ist einer der Mechanismen, um dasselbe zu erreichen. Durch die Vererbung kann der Programmierer zuerst eine allgemeine oder eine Basisklasse erstellen und später auf eine speziellere Klasse erweitern. Es ermöglicht dem Programmierer, besseren Code zu schreiben.

Mit der Vererbung können Sie alle in Ihrer Basisklasse verfügbaren Datenfelder und Methoden verwenden oder erben. Später können Sie eigene Methoden und Datenfelder hinzufügen, sodass die Vererbung eine Möglichkeit bietet, Code zu organisieren, anstatt ihn von Grund auf neu zu schreiben.

Wenn in der objektorientierten Terminologie die Klasse X die Klasse Y erweitert, wird Y als Super- / Eltern- / Basisklasse und X als Unterklasse / Kind- / abgeleitete Klasse bezeichnet. Hierbei ist zu beachten, dass untergeordnete Klassen nur auf Datenfelder und Methoden zugreifen können, die nicht privat sind. Auf private Datenfelder und -methoden kann nur innerhalb der Klasse zugegriffen werden.

Die Syntax zum Erstellen einer abgeleiteten Klasse lautet -

class BaseClass:
   Body of base class
class DerivedClass(BaseClass):
   Body of derived class

Attribute erben

Schauen Sie sich nun das folgende Beispiel an -

Ausgabe

Wir haben zuerst eine Klasse namens Date erstellt und das Objekt als Argument übergeben. Here-object ist eine integrierte Klasse, die von Python bereitgestellt wird. Später haben wir eine weitere Klasse namens time erstellt und die Date-Klasse als Argument aufgerufen. Durch diesen Aufruf erhalten wir Zugriff auf alle Daten und Attribute der Date-Klasse in der Time-Klasse. Aus diesem Grund ist es möglich, die Methode get_date aus dem zuvor erstellten Zeitklassenobjekt tm abzurufen.

Object.Attribute-Suchhierarchie

  • Die Instanz
  • Die Klasse
  • Jede Klasse, von der diese Klasse erbt

Vererbungsbeispiele

Schauen wir uns das Vererbungsbeispiel genauer an -

Lassen Sie uns ein paar Klassen erstellen, um an Beispielen teilzunehmen -

  • Tier - Klasse simuliert ein Tier
  • Katze - Unterklasse des Tieres
  • Hund - Unterklasse des Tieres

In Python wird der Konstruktor der Klasse verwendet, um ein Objekt (eine Instanz) zu erstellen und den Wert für die Attribute zuzuweisen.

Konstruktor von Unterklassen, der immer zu einem Konstruktor der übergeordneten Klasse aufgerufen wird, um den Wert für die Attribute in der übergeordneten Klasse zu initialisieren, und dann beginnt er, einen Wert für seine Attribute zuzuweisen.

Ausgabe

Im obigen Beispiel sehen wir die Befehlsattribute oder -methoden, die wir in die übergeordnete Klasse eingefügt haben, sodass alle Unterklassen oder untergeordneten Klassen diese Eigenschaft von der übergeordneten Klasse erben.

Wenn eine Unterklasse versucht, Methoden oder Daten von einer anderen Unterklasse zu erben, tritt ein Fehler auf, wie wir sehen, wenn die Dog-Klasse versucht, swatstring () -Methoden von dieser cat-Klasse aufzurufen, und es wird ein Fehler ausgegeben (wie in unserem Fall AttributeError).

Polymorphismus ("VIELE FORMEN")

Polymorphismus ist ein wichtiges Merkmal der Klassendefinition in Python, das verwendet wird, wenn Sie Methoden über Klassen oder Unterklassen hinweg gemeinsam benannt haben. Dies ermöglicht es Funktionen, Entitäten unterschiedlichen Typs zu unterschiedlichen Zeiten zu verwenden. So bietet es Flexibilität und lose Kopplung, so dass Code im Laufe der Zeit erweitert und einfach gewartet werden kann.

Auf diese Weise können Funktionen Objekte einer dieser polymorphen Klassen verwenden, ohne die Unterschiede zwischen den Klassen berücksichtigen zu müssen.

Polymorphismus kann durch Vererbung durchgeführt werden, wobei Unterklassen Basisklassenmethoden verwenden oder diese überschreiben.

Lassen Sie uns das Konzept des Polymorphismus anhand unseres vorherigen Vererbungsbeispiels verstehen und eine gemeinsame Methode namens show_affection in beiden Unterklassen hinzufügen -

Aus dem Beispiel, das wir sehen können, bezieht es sich auf ein Design, bei dem Objekte unterschiedlichen Typs auf dieselbe Weise oder genauer gesagt zwei oder mehr Klassen mit einer Methode mit demselben Namen oder einer gemeinsamen Schnittstelle behandelt werden können, weil dieselbe Methode (show_affection im folgenden Beispiel) wird mit beiden Objekttypen aufgerufen.

Ausgabe

Alle Tiere zeigen also Affektionen (show_affection), aber sie machen es anders. Das Verhalten von „show_affection“ ist daher in dem Sinne polymorph, dass es je nach Tier unterschiedlich wirkt. Das abstrakte Konzept „Tier“ bedeutet also nicht „show_affection“, sondern bestimmte Tiere (wie Hunde und Katzen) haben eine konkrete Implementierung der Aktion „show_affection“.

Python selbst hat polymorphe Klassen. Beispiel: Die Funktion len () kann mit mehreren Objekten verwendet werden und alle geben die korrekte Ausgabe basierend auf dem Eingabeparameter zurück.

Überschreiben

Wenn in Python eine Unterklasse eine Methode enthält, die eine Methode der Oberklasse überschreibt, können Sie die Oberklassenmethode auch durch Aufrufen aufrufen

Super (Subclass, self) .method anstelle von self.method.

Beispiel

class Thought(object):
   def __init__(self):
      pass
   def message(self):
      print("Thought, always come and go")

class Advice(Thought):
   def __init__(self):
      super(Advice, self).__init__()
   def message(self):
      print('Warning: Risk is always involved when you are dealing with market!')

Den Konstruktor erben

Wie aus unserem vorherigen Vererbungsbeispiel hervorgeht, befand sich __init__ in der übergeordneten Klasse im oberen Bereich, da der Hund oder die Katze der untergeordneten Klasse keine __init__ -Methode enthielt. Python verwendete die Suche nach Vererbungsattributen, um __init__ in der Tierklasse zu finden. Wenn wir die untergeordnete Klasse erstellt haben, wird zuerst die Methode __init__ in der Hundeklasse angezeigt, dann wurde sie nicht gefunden, dann in die übergeordnete Klasse Animal geschaut und dort gefunden und dort aufgerufen. Da unser Klassendesign komplex wurde, möchten wir möglicherweise eine Instanz initialisieren, die sie zuerst über den übergeordneten Klassenkonstruktor und dann über den untergeordneten Klassenkonstruktor verarbeitet.

Ausgabe

Im obigen Beispiel haben alle Tiere einen Namen und alle Hunde eine bestimmte Rasse. Wir haben den übergeordneten Klassenkonstruktor mit super aufgerufen. Der Hund hat also seine eigene __init__, aber das erste, was passiert, ist, dass wir super nennen. Super ist eine eingebaute Funktion und dient dazu, eine Klasse mit ihrer Superklasse oder ihrer übergeordneten Klasse in Beziehung zu setzen.

In diesem Fall sagen wir, dass wir die Superklasse des Hundes erhalten und die Hundeinstanz an die Methode übergeben, die wir hier sagen, den Konstruktor __init__. Mit anderen Worten, wir nennen die Elternklasse Animal __init__ mit dem Hundeobjekt. Sie fragen sich vielleicht, warum wir nicht einfach Animal __init__ mit der Hundeinstanz sagen, wir könnten dies tun, aber wenn sich der Name der Tierklasse irgendwann in der Zukunft ändern würde. Was ist, wenn wir die Klassenhierarchie neu ordnen wollen, damit der Hund von einer anderen Klasse geerbt wird? Die Verwendung von Super in diesem Fall ermöglicht es uns, die Dinge modular und einfach zu ändern und zu warten.

In diesem Beispiel können wir also allgemeine __init__- Funktionen mit spezifischeren Funktionen kombinieren. Dies gibt uns die Möglichkeit, allgemeine Funktionen von spezifischen Funktionen zu trennen, wodurch Codeduplikationen vermieden und Klassen in einer Weise miteinander verknüpft werden können, die das Gesamtdesign des Systems widerspiegelt.

Fazit

  • __init__ ist wie jede andere Methode; es kann vererbt werden

  • Wenn eine Klasse keinen __init__- Konstruktor hat, überprüft Python die übergeordnete Klasse, um festzustellen, ob sie eine finden kann.

  • Sobald es eines findet, ruft Python es auf und hört auf zu suchen

  • Wir können die Funktion super () verwenden, um Methoden in der übergeordneten Klasse aufzurufen.

  • Möglicherweise möchten wir sowohl in der übergeordneten als auch in unserer eigenen Klasse initialisieren.

Mehrfachvererbung und der Suchbaum

Wie der Name schon sagt, ist Mehrfachvererbung Python, wenn eine Klasse von mehreren Klassen erbt.

Zum Beispiel erbt ein Kind Persönlichkeitsmerkmale von beiden Elternteilen (Mutter und Vater).

Python-Mehrfachvererbungssyntax

Damit eine Klasse von mehreren übergeordneten Klassen erbt, schreiben wir die Namen dieser Klassen in Klammern in die abgeleitete Klasse, während wir sie definieren. Wir trennen diese Namen durch Komma.

Unten ist ein Beispiel dafür -

>>> class Mother:
   pass

>>> class Father:
   pass

>>> class Child(Mother, Father):
   pass

>>> issubclass(Child, Mother) and issubclass(Child, Father)
True

Mehrfachvererbung bezieht sich auf die Fähigkeit, von zwei oder mehr als zwei Klassen zu erben. Die Komplexität entsteht, wenn das Kind von den Eltern und die Eltern von der Klasse der Großeltern erbt. Python klettert auf einen vererbenden Baum und sucht nach Attributen, die zum Lesen von einem Objekt angefordert werden. Es wird die in der Instanz, innerhalb der Klasse, dann der übergeordneten Klasse und zuletzt der Großelternklasse überprüft. Nun stellt sich die Frage, in welcher Reihenfolge die Klassen durchsucht werden - Atem zuerst oder Tiefe zuerst. Standardmäßig geht Python mit der Tiefe zuerst.

Aus diesem Grund durchsucht Python im folgenden Diagramm zuerst die dothis () -Methode in Klasse A. Die Reihenfolge der Methodenauflösung im folgenden Beispiel lautet also

Mro- D→B→A→C

Schauen Sie sich das folgende Diagramm zur Mehrfachvererbung an -

Lassen Sie uns ein Beispiel durchgehen, um die "mro" -Funktion eines Python zu verstehen.

Ausgabe

Beispiel 3

Nehmen wir ein weiteres Beispiel für die Mehrfachvererbung in Rautenform.

Das obige Diagramm wird als mehrdeutig betrachtet. Nach unserem vorherigen Beispiel lautet das Verständnis der „Reihenfolge der Methodenauflösung“ .ie mro D → B → A → C → A, ist es aber nicht. Wenn Python das zweite A vom C erhält, ignoriert es das vorherige A. In diesem Fall lautet das mro also D → B → C → A.

Lassen Sie uns ein Beispiel basierend auf dem obigen Diagramm erstellen -

Ausgabe

Eine einfache Regel zum Verständnis der obigen Ausgabe lautet: Wenn dieselbe Klasse in der Reihenfolge der Methodenauflösung angezeigt wird, werden die früheren Erscheinungen dieser Klasse aus der Reihenfolge der Methodenauflösung entfernt.

Abschließend -

  • Jede Klasse kann von mehreren Klassen erben

  • Python verwendet normalerweise eine "Tiefe zuerst" -Reihenfolge bei der Suche nach ererbenden Klassen.

  • Wenn jedoch zwei Klassen von derselben Klasse erben, entfernt Python die ersten Erscheinungen dieser Klasse aus dem mro.

Dekorateure, statische und Klassenmethoden

Funktionen (oder Methoden) werden durch die def-Anweisung erstellt.

Obwohl Methoden genauso funktionieren wie eine Funktion, mit Ausnahme eines Punktes, an dem das erste Argument der Methode ein Instanzobjekt ist.

Wir können Methoden basierend auf ihrem Verhalten klassifizieren, wie z

  • Simple method- außerhalb einer Klasse definiert. Diese Funktion kann auf Klassenattribute zugreifen, indem sie das Instanzargument eingibt:

def outside_func(():
  • Instance method - -

def func(self,)
  • Class method - wenn wir Klassenattribute verwenden müssen

@classmethod
def cfunc(cls,)
  • Static method - Ich habe keine Informationen über die Klasse

@staticmethod
def sfoo()

Bis jetzt haben wir die Instanzmethode gesehen, jetzt ist es an der Zeit, einen Einblick in die beiden anderen Methoden zu bekommen.

Klassenmethode

Der @ classmethod-Dekorator ist ein integrierter Funktionsdekorator, der die Klasse, für die er aufgerufen wurde, oder die Klasse der Instanz, für die er aufgerufen wurde, als erstes Argument übergibt. Das Ergebnis dieser Auswertung schattiert Ihre Funktionsdefinition.

Syntax

class C(object):
   @classmethod
   def fun(cls, arg1, arg2, ...):
      ....
fun: function that needs to be converted into a class method
returns: a class method for function

Sie haben Zugriff auf dieses cls-Argument. Es kann den Status der Objektinstanz nicht ändern. Das würde den Zugang zu sich selbst erfordern.

  • Es ist an die Klasse gebunden und nicht an das Objekt der Klasse.

  • Klassenmethoden können weiterhin den Klassenstatus ändern, der für alle Instanzen der Klasse gilt.

Statische Methode

Eine statische Methode akzeptiert weder einen self- noch einen cls (class) -Parameter, kann jedoch eine beliebige Anzahl anderer Parameter akzeptieren.

syntax

class C(object):
   @staticmethod
   def fun(arg1, arg2, ...):
   ...
returns: a static method for function funself.
  • Eine statische Methode kann weder den Objektstatus noch den Klassenstatus ändern.
  • Sie sind darauf beschränkt, auf welche Daten sie zugreifen können.

Wann was zu verwenden

  • Wir verwenden im Allgemeinen die Klassenmethode, um Factory-Methoden zu erstellen. Factory-Methoden geben ein Klassenobjekt (ähnlich einem Konstruktor) für verschiedene Anwendungsfälle zurück.

  • Wir verwenden im Allgemeinen statische Methoden, um Dienstprogrammfunktionen zu erstellen.