Aussehen
Vererbung
Ein Labyrinth, voll mit Punkten. Eine gelbe Figur, die sie frisst. Und vier Geister, die hinter ihr her sind. Mehr ist Pac-Man nicht — und genau deshalb baust du es jetzt nach.

Was kommt darin vor? Pac-Man selbst. Die vier Geister — Blinky ist rot, Pinky rosa, Inky türkis, Clyde orange. Dazu die Punkte im Gang und die vier großen Kraftpillen in den Ecken.
Mit dem letzten Kapitel könntest du das schon: Für jede Art von Ding einen Bauplan. Also fängst du bei den Geistern an.
python
class Blinky:
def __init__(self, x, y):
self.name = "Blinky"
self.x = x
self.y = y
self.farbe = "rot"
def bewege(self, dx, dy):
self.x = self.x + dx
self.y = self.y + dy
class Pinky:
def __init__(self, x, y):
self.name = "Pinky"
self.x = x
self.y = y
self.farbe = "rosa"
def bewege(self, dx, dy):
self.x = self.x + dx
self.y = self.y + dyDie beiden Klassen sind Zeile für Zeile gleich — bis auf zwei Wörter. Und jetzt dasselbe noch einmal für Inky. Und für Clyde. Und für Pac-Man, denn auch der steht irgendwo im Labyrinth und bewegt sich Feld für Feld.
Das ist der Zustand, gegen den du schon beim Slalom gearbeitet hast: Schreib nichts zweimal. Hier geht es aber um mehr als um gesparte Tipparbeit.
Am Rand des Labyrinths gibt es einen Tunnel: Wer links hinausläuft, kommt rechts wieder herein. Das sollen alle fünf Figuren können. Bei fünf abgeschriebenen Klassen baust du es fünfmal ein — und die eine, die du vergisst, bleibt an der Wand stehen. Genauso beim Fehler in bewege(): einmal gefunden, viermal repariert, das fünfte Mal übersehen.
Und fällt dir später ein fünfter Geist ein, fängst du wieder von vorne an.
Was du brauchst, ist eine Stelle, an der ein einziges Mal steht, was jede Figur hat und kann. Änderst du dort etwas, können es sofort alle. Und kommt eine neue Art dazu, musst du an dieser Stelle nichts anfassen. Genau dafür gibt es die Vererbung.
Was die fünf teilen und was nicht
Schau die fünf Figuren nebeneinander an und sortiere, was du siehst.
Alle fünf stehen auf einem Feld im Labyrinth und können sich von dort wegbewegen. Das gilt für Pac-Man genauso wie für jeden Geist.
Die vier Geister haben darüber hinaus etwas, das im Bauplan von Pac-Man nichts zu suchen hätte: eine Farbe. Pac-Man ist immer gelb, es gibt nur einen von ihm. Die Geister dagegen erkennst du im Spiel ausschließlich an der Farbe — und die bleibt nicht einmal gleich: Frisst Pac-Man eine Kraftpille, werden alle vier blau und laufen weg.
Und die vier Geister untereinander unterscheiden sich in genau einer einzigen Sache: darin, welche Farbe sie mitbringen.
Aus dieser Sortierung wird ein Baum. Was alle teilen, kommt nach oben; was nur einige teilen, in die Mitte; was einzeln ist, ganz nach unten.
Das Gemeinsame nach oben
Jetzt derselbe Baum in Python. Ganz oben steht das, was für alle fünf gilt:
python
class Figur:
def __init__(self, name, x, y):
self.name = name
self.x = x
self.y = y
def bewege(self, dx, dy):
self.x = self.x + dx
self.y = self.y + dy
def vorstellen(self):
print(self.name, "steht auf Feld", self.x, self.y)In dieser Klasse steht kein Wort über Geister und keins über Pac-Man. Sie beschreibt nur, was alle fünf teilen.
Der Geist baut darauf auf. Der Klassenname in den Klammern sagt: Diese Klasse baut auf jener auf.
python
class Geist(Figur):
def __init__(self, name, x, y, farbe):
super().__init__(name, x, y)
self.farbe = farbe
def fliehen(self):
# Pac-Man hat eine Kraftpille gefressen.
self.farbe = "blau"Geist schreibt nur hin, was am Geist besonders ist: die Farbe und das Fliehen. Name, Feld und Bewegung hat er schon.
super() steht für die Oberklasse. super().__init__(name, x, y) heißt: Lass erst den Konstruktor von Figur seine Arbeit tun — Name und Feld setzen — und ergänze danach das Eigene, die Farbe.
Vergisst du diese Zeile, hat dein Geist keinen Namen und kein Feld, auf dem er steht, und die erste Bewegung bricht ab. Das ist der häufigste Fehler bei der Vererbung überhaupt.
python
blinky = Geist("Blinky", 13, 11, "rot")
blinky.bewege(0, -1)
blinky.vorstellen()Auf dem Bildschirm steht Blinky steht auf Feld 13 10. Bemerkenswert daran: bewege() und vorstellen() kommen in Geist überhaupt nicht vor — und funktionieren trotzdem. Python schaut zuerst in der Klasse des Objekts nach und, wenn es dort nichts findet, eine Stufe höher. Bei blinky.bewege() wird es erst in Figur fündig.
Vererbung
Bei der Vererbung baut eine neue Klasse auf einer bestehenden auf. Sie übernimmt deren Attribute und Methoden und ergänzt oder ändert sie, ohne dass etwas erneut geschrieben werden muss.
Die Klasse oben heißt Oberklasse oder Basisklasse, die darauf aufbauende Unterklasse oder abgeleitete Klasse.
super()
super() steht für die Oberklasse. Ruft eine Unterklasse in ihrem Konstruktor super().__init__(...) auf, lässt sie zuerst die Oberklasse ihre Arbeit tun und ergänzt danach ihr Eigenes.
Aufgabe
Was passiert, wenn super() fehlt, erkennt man später schneller, wenn man den Fehler einmal absichtlich gemacht hat.
Der Ist-ein-Test
Ob Vererbung passt, prüfst du mit einem Satz: Blinky ist ein Geist. Ein Geist ist eine Figur. Beides stimmt, also darf der Baum so stehen.
Gegenprobe: Ein Rad ist ein Auto. Das stimmt nicht — ein Auto hat vier Räder. Bei „hat ein" gehört das Rad als Attribut in die Autoklasse und nicht als Oberklasse darüber. Wer das verwechselt, baut Klassenbäume, in denen niemand mehr etwas findet.
Überschreiben
Ein Ärgernis bleibt: blinky.vorstellen() sagt kein Wort über die Farbe. Wie auch — vorstellen() steht in Figur, und Figur weiß nichts von Farben.
Also schreibt Geist eine eigene Fassung mit demselben Namen hin:
python
class Geist(Figur):
def __init__(self, name, x, y, farbe):
super().__init__(name, x, y)
self.farbe = farbe
def vorstellen(self):
print(self.name, "ist", self.farbe, "und steht auf Feld", self.x, self.y)
def fliehen(self):
# Pac-Man hat eine Kraftpille gefressen.
self.farbe = "blau"Für Geister gilt jetzt die nähere Fassung, für Pac-Man weiterhin die aus Figur. Python nimmt immer die erste, die es findet, und sucht dabei von unten nach oben.
python
blinky = Geist("Blinky", 13, 11, "rot")
blinky.vorstellen()
blinky.fliehen()
blinky.vorstellen()Blinky ist rot und steht auf Feld 13 11
Blinky ist blau und steht auf Feld 13 11Überschreiben
Definiert eine Unterklasse eine Methode, die es in der Oberklasse schon gibt, ersetzt sie diese für Objekte der Unterklasse. Man sagt, sie überschreibt die Methode.
Die vier Geister
Bisher gibt es nur die Klasse Geist. Die vier einzelnen Geistarten fehlen noch — und die unterscheiden sich in genau einem Wort:
python
class Blinky(Geist):
def __init__(self, x, y):
super().__init__("Blinky", x, y, "rot")
class Pinky(Geist):
def __init__(self, x, y):
super().__init__("Pinky", x, y, "rosa")Blinky legt nur noch fest, wie er heißt und welche Farbe er mitbringt. Alles andere reicht er nach oben durch. Beim Anlegen brauchst du die Farbe deshalb nicht mehr zu nennen: Ein Blinky ist rot, das weiß er selbst.
python
geister = [Blinky(13, 11), Pinky(14, 11)]
for geist in geister:
geist.vorstellen()Die Schleife weiß nicht, wen sie vor sich hat. Jedes Objekt weiß es selbst und antwortet auf seine Weise. In einem fertigen Spiel steht in dieser Schleife nicht print, sondern der Zug, den der Geist in diesem Augenblick macht.
Die vier hängen dabei nebeneinander unter Geist — sie erben nichts voneinander, sondern alle vom selben Ort. Solche Klassen nennt man Geschwisterklassen. Auch das entscheidet der Ist-ein-Test: Ein Blinky ist ein Pinky ist falsch, ein Blinky ist ein Geist ist richtig.
Aufgabe
Pac-Man kommt dazu
Der Baum hat noch einen zweiten Ast. Pac-Man ist eine Figur wie die Geister, bringt aber etwas anderes Eigenes mit: einen Punktestand.
python
class PacMan(Figur):
def __init__(self, name, x, y):
super().__init__(name, x, y)
self.punkte = 0
def frisst(self):
self.punkte = self.punkte + 10Achte darauf, was du dafür anfassen musstest: nichts. An Figur keine Zeile, an Geist keine, an Blinky und Pinky keine. Genau das war das Versprechen vom Anfang — eine neue Art kommt dazu, ohne dass das Bestehende in Gefahr gerät.
Andersherum gilt es genauso. Soll jede Figur durch den Tunnel am Rand laufen können, schreibst du das ein einziges Mal in Figur. Danach können es Pac-Man und alle vier Geister.
Zum Nachsehen an einem echten Baum
Die quelloffene Spiele-Engine Godot druckt bei jeder Klasse ihre Abstammung mit ab. Bei Sprite2D — einem Bild, das sich in der Spielwelt herumschieben lässt — steht dort die Zeile Inherits: Node2D < CanvasItem < Node < Object. Vier Stufen über sich, von links nach rechts immer allgemeiner. Genau das, was du hier gebaut hast, nur höher.
Noch mehr üben
Aufgabe
Aufgabe