Datenklassenvererbung in Python
- Vererbung in Python
- Vererbung auf mehreren Ebenen in Python
- Mischen Sie Standard- und Nicht-Standardattribute zwischen Basisklasse und Unterklasse mithilfe der Datenklassenvererbung in Python
- Abschluss
In den Versionen 3.7 und höher wurde die Datenklassen-Vererbung in Python eingeführt. In diesem Artikel werden mehrstufige Vererbungen und die Verwendung der Datenklassenvererbung in Python ausführlich erläutert.
Vererbung in Python
Die Vererbung von Datenklassen in Python wird verwendet, um Daten in Unterklassen von ihrer übergeordneten Klasse abzurufen, was dazu beiträgt, sich wiederholende Codes zu reduzieren und Code wiederverwendbar zu machen.
Schauen wir uns ein Beispiel für Vererbung an:
Das Programm importiert das Bibliothekspaket dataclass
, um die Erstellung dekorierter Klassen zu ermöglichen. Die erste hier erstellte Klasse ist Parent
, die zwei Member-Methoden hat - String name
und Integer Alter
.
Dann wird hier eine Unterklasse von Parent
erstellt. Die Klasse Kind
führt eine neue Mitgliedsmethode ein – Schule
.
Für die Klasse Parent
wird ein Instanzobjekt jack
erzeugt, das zwei Argumente an die Klasse übergibt. Ein weiteres Instanzobjekt, jack_son
, wird für die Klasse Child
erstellt.
Da die Klasse Child
eine Unterklasse von Parent
ist, können die Datenelemente in der Klasse Child
abgeleitet werden. Dies ist das Hauptmerkmal der Datenklassenvererbung in Python.
from dataclasses import dataclass
@dataclass
class Parent:
name: str
age: int
def print_name(self):
print(f"Name is '{self.name}' and age is= {self.age}")
@dataclass
class Child(Parent):
school: str
jack = Parent("Jack snr", 35)
jack_son = Child("Jack jnr", 12, school="havard")
jack_son.print_name()
Ausgang:
C:\python38\python.exe "C:/Users/Win 10/PycharmProjects/class inheritance/2.py"
Name is 'Jack jnr' and age is= 12
Process finished with exit code 0
Vererbung auf mehreren Ebenen in Python
Da wir gesehen haben, wie die Vererbung von Datenklassen in Python funktioniert, werden wir uns nun das Konzept der mehrstufigen Vererbung ansehen. Es ist eine Art der Vererbung, bei der eine aus einer übergeordneten Klasse erstellte Unterklasse als übergeordnete Klasse für die nachfolgende Enkelklasse verwendet wird.
Das folgende Beispiel demonstriert die mehrstufige Vererbung in einfacher Form:
Elternklasse
Eine Klasse Parent
wird mit einem Konstruktor __init__
und einer Member-Methode – print_method
– erstellt. Der Konstruktor gibt die Anweisung "Initialized in Parent"
aus, damit sie angezeigt wird, wenn die Klasse von ihrer untergeordneten Klasse aufgerufen wird.
Die Funktion print_method
hat einen Parameter b
, der gedruckt wird, wenn diese Methode aufgerufen wird.
Kinderklasse
Die Klasse Child
ist von Parent
abgeleitet und gibt eine Anweisung in ihrem Konstruktor aus. Die super().__init__
bezieht sich auf die Basisklasse mit der Kindklasse.
Wir verwenden super()
, damit alle potenziellen kooperativen Mehrfachvererbungen, die von untergeordneten Klassen verwendet werden, die entsprechende nächste Funktion der übergeordneten Klasse in der Method Resolution Order (MRO) aufrufen.
Die Member-Methode print_method
ist überladen, und eine print-Anweisung gibt den Wert von b
aus. Auch hier bezieht sich super()
auf die Member-Methode ihrer Elternklasse.
Enkelklasse
An diesem Punkt erstellt das Programm nur Boilerplates (Wiederholungscodes) der Struktur, um eine weitere geerbte Klasse aus der Klasse Child
zu erstellen. Innerhalb von print_method
wird der Wert von b
mit super()
erhöht.
Hauptfunktion
Zuletzt wird die Funktion main
erstellt, die ein Objekt ob
erstellt und zu einer Instanz von GrandChild()
gemacht wird. Zuletzt ruft das Objekt ob
die print_method
auf.
So werden mehrstufige Klassen gestapelt, wenn die Datenklassenvererbung in Python verwendet wird.
class Parent:
def __init__(self):
print("Initialized in Parent")
def print_method(self, b):
print("Printing from class Parent:", b)
class Child(Parent):
def __init__(self):
print("Initialized in Child")
super().__init__()
def print_method(self, b):
print("Printing from class Child:", b)
super().print_method(b + 1)
class GrandChild(Child):
def __init__(self):
print("Initialized in Grand Child")
super().__init__()
def print_method(self, b):
print("Printing from class Grand Child:", b)
super().print_method(b + 1)
if __name__ == "__main__":
ob = GrandChild()
ob.print_method(10)
Ausgang:
C:\python38\python.exe "C:/Users/Win 10/PycharmProjects/class inheritance/3.py"
Initialized in Grand Child
Initialized in Child
Initialized in Parent
Printing from class Grand Child: 10
Printing from class Child: 11
Printing from class Parent: 12
Process finished with exit code 0
Lassen Sie uns verstehen, was der Code hier tut:
Die Funktion main
übergibt den Wert 10
an die Funktion print_method
der Klasse Grand Child
. Gemäß der MRO (Method Resolution Order) führt das Programm zuerst die Klasse Grand Child
aus, gibt die __init__
-Anweisung aus und geht dann zu ihrer Elternklasse über – der Child
-Klasse.
Die Klassen Child
und Parent
geben ihre __init__
-Anweisungen gemäß MRO aus, und dann folgt der Compiler zurück zur print_method
der Klasse GrandChild
. Diese Methode gibt 10
(den Wert von b
) aus und verwendet dann super()
, um den Wert von b
in ihrer Oberklasse, der Child
-Klasse, zu erhöhen.
Dann geht der Compiler weiter zur print_method
der Child
-Klasse und gibt 11
aus. Dann gibt es in der letzten Ebene von MRO die Klasse Parent
, die 12
druckt.
Das Programm wird beendet, da keine Oberklasse über der Klasse Eltern
existiert.
Da wir verstanden haben, wie die Vererbung auf mehreren Ebenen bei der Vererbung von Datenklassen in Python funktioniert, behandelt der nächste Abschnitt das Konzept der Vererbung von Attributen von einer übergeordneten Klasse und wie man es ändert.
Mischen Sie Standard- und Nicht-Standardattribute zwischen Basisklasse und Unterklasse mithilfe der Datenklassenvererbung in Python
Wir haben gesehen, wie eine untergeordnete Klasse für den Zugriff auf Datenelemente ihrer übergeordneten Klasse bei der Datenklassenvererbung in Python verwendet wird und wie die Vererbung auf mehreren Ebenen funktioniert. Nun stellt sich die Frage, ob eine untergeordnete Klasse auf Datenelemente ihrer Oberklasse zugreifen kann, kann sie Änderungen daran vornehmen?
Die Antwort ist ja, aber TypeErrors müssen vermieden werden. Zum Beispiel gibt es im untenstehenden Programm zwei Klassen, eine Eltern
-Klasse und eine Unterklasse Kind
.
Die Klasse Eltern
hat drei Datenelemente – name
, Alter
und eine Bool-Variable ugly
, die standardmäßig auf False
gesetzt ist. Drei Member-Methoden geben name
, Alter
und ID aus.
Jetzt wird innerhalb der dekorierten Klasse Child
, die von Parent
abgeleitet ist, ein neues Datenelement eingeführt – school
. Damit ändert die Klasse das Attribut der Variable ugly
von False
auf True
.
Zwei Objekte, jack
für Parent
und jack_son
für Child
, werden erstellt. Diese Objekte übergeben Argumente an ihre Klassen, und beide Objekte rufen die Methode print_id
auf und geben die Details aus.
Ein Hauptproblem bei der Verwendung dieser Methode zum Ändern von Standardwerten der Basisklasse besteht darin, dass sie einen TypeError verursacht.
from dataclasses import dataclass
@dataclass
class Parent:
name: str
age: int
ugly: bool = False
def print_name(self):
print(self.name)
def print_age(self):
print(self.age)
def print_id(self):
print(f"ID: Name - {self.name}, age = {self.age}")
@dataclass
class Child(Parent):
school: str
ugly: bool = True
jack = Parent("jack snr", 32, ugly=True)
jack_son = Child("Mathew", 14, school="cambridge", ugly=True)
jack.print_id()
jack_son.print_id()
Ausgang:
raise TypeError(f'non-default argument {f.name!r} '
TypeError: non-default argument 'school' follows default argument
Ein Grund für diesen Fehler ist, dass bei der Datenklassenvererbung in Python die Attribute aufgrund der Art und Weise, wie Datenklassen Attribute mischen, nicht mit Standardwerten in einer Basisklasse und dann ohne Standardwert (Positionsattribute) in einer Unterklasse verwendet werden können.
Dies liegt daran, dass die Attribute von Anfang an unten im MRO zusammengeführt werden und eine geordnete Liste von Attributen in der Reihenfolge aufbauen, in der sie zuerst gesehen werden, wobei Überschreibungen an ihren ursprünglichen Positionen verbleiben.
Mit hässlich
als Standard beginnt der Elternteil
mit name
, Alter
und hässlich
, und dann fügt das Kind
am Ende dieser Liste Schule
hinzu (wobei hässlich
bereits in der Liste).
Dies führt dazu, dass name
, Alter
, hässlich
und Schule
in der Liste stehen, und da Schule
keinen Standardwert hat, listet die __init__
-Funktion das Ergebnis als falschen Parameter auf.
Wenn der Decorator @dataclass
eine neue Datenklasse erstellt, durchsucht er alle Basisklassen der Klasse in umgekehrter MRO (beginnend beim Objekt) und fügt die Felder aus jeder Basisklasse zu einer geordneten Zuordnung von Feldern für jede Datenklasse hinzu findet.
Es fügt dann seine Felder der geordneten Zuordnung hinzu, nachdem alle Basisklassenfelder hinzugefügt wurden. Diese kombinierte berechnete geordnete Zuordnung von Feldern wird von allen erstellten Methoden verwendet.
Aufgrund der Anordnung der Felder ersetzen abgeleitete Klassen Basisklassen.
Wenn ein Feld ohne Standardwert auf ein Feld mit Standardwert folgt, wird ein TypeError generiert. Dies gilt unabhängig davon, ob dies in einer einzelnen Klasse oder aufgrund von Klassenvererbung geschieht.
Die erste Alternative, um dieses Problem zu umgehen, besteht darin, die Felder mit Standardwerten an eine spätere Position im MRO-Auftrag zu zwingen, indem andere Basisklassen verwendet werden. Vermeiden Sie auf jeden Fall, Felder direkt auf Klassen zu setzen, die als Basisklassen verwendet werden, wie z. B. Parent
.
Dieses Programm hat Basisklassen mit Feldern und Felder ohne Standardwerte werden getrennt. Öffentliche Klassen leiten sich von den Klassen Basis mit
und Basis ohne
ab.
Die Unterklassen der öffentlichen Klasse stellen die Basisklasse in den Vordergrund.
from dataclasses import dataclass
@dataclass
class _ParentBase:
name: str
age: int
@dataclass
class _ParentDefaultsBase:
ugly: bool = False
@dataclass
class _ChildBase(_ParentBase):
school: str
@dataclass
class _ChildDefaultsBase(_ParentDefaultsBase):
ugly: bool = True
@dataclass
class Parent(_ParentDefaultsBase, _ParentBase):
def print_name(self):
print(self.name)
def print_age(self):
print(self.age)
def print_id(self):
print(f"ID: Name - {self.name}, age = {self.age}")
@dataclass
class Child(_ChildDefaultsBase, Parent, _ChildBase):
pass
Amit = Parent("Amit snr", 32, ugly=True)
Amit_son = Child("Amit jnr", 12, school="iit", ugly=True)
Amit.print_id()
Amit_son.print_id()
Ausgang:
C:\python38\python.exe "C:/main.py"
The Name is Amit snr and Amit snr is 32 year old
The Name is Amit jnr and Amit jnr is 12 year old
Process finished with exit code 0
Die hier erstellte MRO priorisiert Felder ohne Standardwerte gegenüber Feldern mit Standardwerten, indem sie die Felder in separate Basisklassen mit Feldern ohne Standardwerte
und mit Standardwerten
aufteilt und die Vererbungsreihenfolge sorgfältig auswählt. Die MRO des Kindes
ist:
<class 'object'>
||
<class '__main__._ParentBase'>,
||
<class '__main__._ChildBase'>
||
<class '__main__._ParentDefaultsBase'>,
||
<class '__main__.Parent'>,
||
<class '__main__._ChildDefaultsBase'>,
||
<class '__main__._Child'>
Obwohl Parent
keine neuen Felder erstellt, erbt es die Felder von ParentDefaultsBase
und sollte in der Reihenfolge der Feldauflistung nicht an letzter Stelle stehen. So wird die ChildDefaultsBase
zuletzt beibehalten, um den richtigen Auftragstyp zu erfüllen.
Auch die Datenklassenregeln werden erfüllt, da die Klassen ParentBase
und ChildBase
, die Felder ohne Vorgabe haben, vor ParentDefaultsBase
und ChildDefaultsBase
stehen, die Felder mit Vorgabe haben.
Infolgedessen ist Child
immer noch eine Unterklasse von Parent
, während die Klassen Parent
und Child
eine korrekte Feldreihenfolge haben:
# __ Program Above __
print(signature(Parent))
print(signature(Child))
Ausgang:
Abschluss
Dieser Artikel erklärt die Vererbung von Datenklassen in Python im Detail. Konzepte wie Datenklasse, untergeordnete Klassen, Vererbung auf mehreren Ebenen und das Mischen von Attributen von Basisklasse zu Unterklasse werden ausführlich erklärt.
Verwandter Artikel - Python Class
- Abstrakte Python-Eigenschaft
- Python-Generator-Klasse
- Python-Klassenfabrik
- Python-Klassengleichheit
- Serialisiert ein Python-Klassenobjekt in JSON