|
|
Klasseninstanzen, die ihren eigenen Namen kennen |
|---|
Nachdem man genauere Vorstellungen hat, wie
Klasseninstanzen überhaupt miteinander reden, kann man das nun
weiter verfolgen. Vorneweg, das nachfolgend Beschriebene ist
natürlich, wie so oft, nicht der einzige Weg. Man kann das total
umgehen und ganz anders machen. Aber es geht eben auch so, wie hier
erläutert. Und dieser Weg hat eben auch seinen Reiz.
Wozu man das brauchen kann, wenn Klasseninstanzen ihren eigenen
Variablennamen wissen? Na so kann solch ein Objekt z.B. einen
Eintrag mit seinem eigenen Namen in ein Dictionary vornehmen, so dass
das Objekt nun in einem Team von Objekten eingereiht ist, die
periodisch alle eine definierte Arbeit ausführen, indem eine
Funktion das Dictionary durchmustert und sämtliche eingetragenen
Objekte nacheinander mit ihrer jeweiligen work() - Funktion aufruft und
die arbeiten dann brav. So etwas habe ich schon mal verwendet für
ein Simulationsprogramm, in dem Knoten vernetzt waren und die alle
nacheinander aufgerufen wurden und dabei verschiedenartige Funktionen
ausgeführt haben. Waren alle einmal abgearbeitet, befand sich das
Netz im Zustand n + 1. Und dann ging es wieder von vorn los. Wollte
sich ein Objekt aus der Arbeitsschleife abmelden, hat es seinen Namen
einfach aus der Teilnahmeliste (Dictionary) entfernt. Ist ja fast wie
im richtigen Leben :-). Ebenso steht der Objektname auch für
konkurrierende Objekte zur Verfügung. Wer kennt nicht die
schönen Aquarien als Bildschirmschoner. Wird der kleine Fisch vom
größeren gefressen (jeder Fisch ist eine eigene Instanz
seiner Klasse), wird dessen Leben einfach vom großen Fisch
ausgehaucht. Er killt das Objekt aus der Liste der lebenden Fische.
Ein Generator, der z.B. die Gesamtzahl der existierenden Fische
überwacht, erzeugt dann bald einen neuen Fisch derselben Art. der
dann am linken Rand einfach neu auftaucht.
Ein anderes Beispiel wären Objekte, die in einem Wegenetz
verbunden sind und die eine Wegesuche vollziehen sollen. Kennt der
Knoten seinen eigenen Namen, dann kann er z.B. Wegevarianten verwerfen,
die auf ihn selbst zurückkehren (also zirkular sind).
Und wie kann man dazu kommen? Ein kurzes vereinfachtes Beispiel ist
bei den Erläuterungen
zur exec - Anweisung angedeutet. Andere
Varianten gehen auch ohne exec - Anweisung (die aus meiner Sicht
recht unelegant wirkt). Eine davon verwendet die eingebaute
Funktion apply(), eine andere Variante funktioniert so, dass sich
die Instanzen bei der Initialisierung in ein globales Objekt (z.B.
eine Liste) hinten eintragen und dabei aus der Länge der Liste
ihre Positionsnummer in der Liste ermitteln.
Das sieht dann etwa so aus:
# Hierarchie von Einträgen
all = []
# Das ist die globale Variable
class knoten:
def __init__(self, text, vater):
self.vor = vater
self.text = text
self.kind = []
global all
self.nr = len(all)
all.append(self)
# nicht
die eigene Nummer wird eingetragen, sondern die Instanz selbst
def zeige(self):
global all
if self.vor > -1:
vatername = all[self.vor].text
else:
vatername = 'none'
return str(self.nr) + '#' +
self.text + ' mit Vater: ' + vatername
def neukind(self, text):
p = knoten(text, self.nr)
self.kind.append(p)
k = knoten('root', -1)
eltern = ['vater', 'mutter']
# hier drin steckt noch die
Idee, die Mehrfachvererbung anzuwenden
# (hier: ein Objekt hat mehrere
Eltern, was beim Löschen
# auch mit zu beachten ist!
kinder = ['sohn', 'schwiegertochter']
enkel = ['enkel']
for i in eltern:
p = knoten(i, 0)
all[1].neukind('michael')
for i in all:
print i.zeige()
In den klassischen Programmiersprachen wäre ein vergleichbarer Lösungsansatz ein Array mit Zeigern gewesen, die auf die jeweiligen work() - Funktionen gezeigt hätten. Mit Aufrufen dieser Funktionsadressen wären die Funktionen dann ausgeführt worden. Das ließ sich aber nicht mit wenigen Zeilen programmieren!
Es gibt auch noch eine Vorgehensweise, in der sich die Objekte nicht
gegenseitig mit ihren Namen aufrufen. Das wird dann so gelöst,
dass die ganze Struktur (Hirarchie oder Vernetzung) in einer passiven
Variablen gehalten wird (z.B. Dictionary oder verschachtelte Listen)
und ein "Überobjekt" in dieser Datenstruktur navigiert. Das
heißt es wird anstelle der o.g. Namen von Objekten jetzt mit
Positionsnummern in der Liste oder mit Keys des Dictionarys gearbeitet.
Dann erkennt das Navigationsobjekt abhängig von seiner Stellung
in der Datenstruktur die jeweiligen Möglichkeiten, in die
nächste Postion zu wechseln.