Vererbung weiterdenken! Erben von Listen etc.
Wir haben bisher fleißig aus von uns erstellten Klassen geerbt. Aber Vererbung in Python kann man noch weiterdenken! Die daraus entstehenden Möglichkeiten wird man erst nach und nach erfassen (wirklich).
Hier einfach mal zum Kennenlernen. Aber Schritt für Schritt!
Der große Vorteil von objektorientierter Programmierung haben wir am Anfang vom Kapitel gesehen, dass wir benötigte Datenstrukturen passend zu unserem Objekt (was Realität abbildet) zusammenbauen können.
Einen Schritt zurück. Schauen wir uns den Datentyp Liste an.
datenliste = ["Hans", "Elke", "Sonja", "Kai"]
print(dir(datenliste))
Über die Anweisung dir()
sehen wir die verfügbaren Methoden (es handelt sich bei Listen auch im Objekte, was man auch in der Anwendung sieht).
Das Ergebnis ist:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
Wir können zum Beispiel die Daten der Liste auslesen über die Methode pop()
:
datenliste = ["Hans", "Elke", "Sonja", "Kai"]
print(datenliste)
print(datenliste.pop())
print(datenliste)
Die Anweisung pop()
liest das letzte Element aus und wirft es aus der Liste:
['Hans', 'Elke', 'Sonja', 'Kai']
Kai
['Hans', 'Elke', 'Sonja']
Schauen wir uns eine Klasse an mit einer ähnlichen Datenstruktur. Wir basteln uns einen sportiven Jogger, der durch die Welt läuft und gelaufene Zeiten sammelt. Hier haben wir in unserer Klasse eine Liste mit dem Namen gelaufene_zeiten
und einer Methode zeiterfassung()
.
class Jogger():
""" sportliche Klasse für das Verwalten von gelaufenen Zeiten """
def __init__(self, altersklasse, zeit=[]):
self.altersklasse = altersklasse
self.gelaufene_zeiten = zeit
def zeiterfassen(self, zeiten):
self.gelaufene_zeiten += zeiten
Wir sehen bei der __init__
, dass unsere übergebene Zeit eine Liste ist (die eckigen Klammern verraten dies).
Jetzt erstellen wir die Jogger-Instanz – unser Objekt heißt „Laeufer_Hans“
class Jogger():
""" sportliche Klasse für das Verwalten von gelaufenen Zeiten """
def __init__(self, altersklasse, zeit=[]):
self.altersklasse = altersklasse
self.gelaufene_zeiten = zeit
def zeiterfassen(self, zeiten):
self.gelaufene_zeiten += zeiten
Laeufer_Hans = Jogger("M40")
print(Laeufer_Hans.altersklasse)
Laeufer_Hans.zeiterfassen(["2:30"])
print(Laeufer_Hans.gelaufene_zeiten)
Laeufer_Hans.zeiterfassen(["2:40", "3:10"])
print(Laeufer_Hans.gelaufene_zeiten)
Als Ergebnis sehen wir die Altersklasse (das ist das Teil, damit Läufer sich untereinander vergleichen können – sprich unser Läufer ist zwischen 40 und 50 Jahre alt. Und seine gesammelten Zeiten:
M40
['2:30']
['2:30', '2:40', '3:10']
Lassen wir uns über dir()
ausgeben, was so an Methoden und Eigenschaften unsere Klasse und unser Objekt hat:
print(dir(Jogger))
print(dir(Laeufer_Hans))
Als Ergebnis bekommen wir:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'zeiterfassen']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'altersklasse', 'gelaufene_zeiten', 'zeiterfassen']
Und das Ganze übersichtlicher:
Die Klasse Jogger hat:
- die Methode „zeiterfassung“
Das Objekt „Laeufer_Hans“ hat:
- die Methode „zeiterfassung“ (logisch, ist ja aus Klasse „Jogger“ entstanden)
- die Eigenschaft „altersklasse“
- die Eigenschaft „gelaufene_zeiten“
Wenn wir nun für die Eigenschaft „gelaufene_zeiten“ Methoden wie es die Datenstruktur „Liste“ anbietet gerne anwenden würden, müssten wir selber neue Methoden schreiben. Aber Faulheit siegt (zumindest, wenn man irgendwann auch mal Feierabend haben möchte).
Methoden von Datentyp „Liste“ erben
Also wollen wir die Methoden des Datentyps Liste („list“) erben. Unsere Klasse Jogger soll also ein Kindelement von „list“ werden.
class Jogger(list):
Lassen wir uns jetzt wieder die Möglichkeiten des Objekts über dir()
ausgeben:
print(dir(Jogger))
Jetzt stehen uns neben „zeiterfassung()“ auch alle Methoden von „list” zur Verfügung:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort', 'zeiterfassen']
Und diese wenden wir nun auch an – unser kompletter Code:
class Jogger(list):
""" sportliche Klasse für das Verwalten von gelaufenen Zeiten """
def __init__(self, altersklasse, zeit=[]):
self.altersklasse = altersklasse
self.gelaufene_zeiten = zeit
def zeiterfassen(self, zeiten):
self.gelaufene_zeiten += zeiten
Laeufer_Hans = Jogger("M40")
Laeufer_Hans.zeiterfassen(["2:30"])
Laeufer_Hans.zeiterfassen(["2:40", "3:10"])
# print(dir(Jogger))
print()
print("vor POP:")
print(Laeufer_Hans.gelaufene_zeiten)
print("POP:")
print(Laeufer_Hans.gelaufene_zeiten.pop())
print("nach POP:")
print(Laeufer_Hans.gelaufene_zeiten)
Und als Ergebnis erhalten wir wie erwartet nach der allgemeinen Methode pop()
, die uns das Objekt „Liste“ zur Verfügung stellt:
vor POP:
['2:30', '2:40', '3:10']
POP:
3:10
nach POP:
['2:30', '2:40']
Am Rande: die Methode pop()
würde auch so in der Klasse zu Verfügung stehen :). Hier sieht man auf jeden Fall, wie weit Klassen erben können und ich denke, das Wissen darum kann sehr hilfreich sein.