Zugriff eines Objekts auf Elemente des umschließenden Objekts in Python 3

D

Dexter1997

Gast
Hallo Freunde der Sonne,

Ich habe ein Objekt. In diesem Objekt ist ein Objekt (einer anderen Klasse) in einem Attribut gespeichert. Die Methoden dieser Objekte sollten idealerweise auf die Attribute des umschließenden Objekts zugreifen können (ohne Parameterübergabe, ohne Angabe des genauen Objektnamens vor dem Objektattribut). Wie kann man das syntaktisch mit Python realisieren? Oder geht das evtl. garnicht? Ich fandu dazu im Internet nichts aufschlußreiches. Gebrauchen könnte ich sowas aber.
 
Dem inneren Objekt eine Referenz auf das umschließende Objekt mitgeben!?
Irgendwas war da dann aber im Kontext der Gargabe Collection noch zu beachten. Kann nur nicht mehr genau sagen, ob das nur ältere Python Versionen betrifft. Irgendwas mit "weakref" oder so.

Hilfreich wäre aber sicherlich noch zu wissen, für welches Szenario du das brauchst. Vielleicht gibts eine schönere Variante für dein Problem!?
 
Ich programmiere ein Rollenspiel. Ich habe eine Lebewesen-Klasse, die sozusagen die Handelnden im Spiel, eingeschlossen den Spieler selbst, darstellen sollen. Diese Lebewesen sollen unter anderem gegeneinander kämpfen. Dazu haben sie Fähigkeiten. Die Fähigkeiten, beispielsweise einen Feurpfeil und einen Feuerball zu wirken oder sich selbst zu heilen, sind solche. Fähigkeiten können verbessert werden, und haben daher beispielsweise einen Wert "Stufe" als Attribut, gleichzeitig kostet das Wirken einer Fähigkeit Manapunkte, über die der Spieler verfügt. Das Wirken der Fähigkeit, die beispielsweise den resultierenden Schaden an eine Methode "erleide_Schaden()" des Feindes zurückgibt, sieht also unter anderem eine Absenkung des Manavorrats des Lebewesens vor, wobei das Lebewesen über Mana verfügt, und nicht die Fähigkeit selbst. Man müßte der "wirken"-Methode einer Fähigkeit also immer das Mana des Lebewesens als Parameter mitgeben, um nur einen Nachteil zu nennen. Dieser Schreibaufwand ließe sich vermeiden, wenn innerhalb der Methode auf die Attribute des Objekts, das die Fähigkeiten besitzt, zugegriffen werden könnte.
 
Wäre es nicht sinnvoller Fähigkeit zu einem Valueobjekt zu machen und das Lebewesen Zauber wirken zu lassen?
 
Was heißt das? Auch der Wikipediaartikel läßt mich nicht schlau werden aus deinem Rat :(

https://de.wikipedia.org/wiki/Value_Object

Falls du eine innere Klasse meinst: Es soll in Python so angeblich nicht möglich sein, eine innere Klasse zu schreiben, die auf die Attribute der umschließenden Klasse zugreifen kann. Das wäre ansonsten natürlich eine gute Lösung, wenn das gehen würde.
 
Entschuldige, ich meinte nicht Valueobjekt, sondern ein Objekt, dass selbst keine wesentlichen Methoden besitzt, sondern nur Daten speichert (vgl. struct z.B. in C). Ich denke, deine Fähigkeiten-Klasse sollte nur die Informationen zur Fähigkeit haben, die Ausübung der Fähigkeit hingegen gehört meiner Meinung nach in die Lebewesen-Klasse.
Sollten sich die Ausüben-Funktionen der Fähigkeitsklassen zu sehr unterscheiden, könnte man Ausübung dennoch in der Lebewesen-Klasse anstoßen, die eigentliche Ausführung aber an eine Fähigkeiten-Methode delegieren.
 
Zuletzt bearbeitet:
Das ist eine gute Idee. Wäre es dennoch möglich, eine Art innere Klasse ähnlich wie in Java in Python 3 zu realisieren?
 
Innere Klassen gibt es auch in Python. Allerdings erfüllen sie meist einen anderen Zweck als in Java, nämlich um den Namensraum sauber zu halten. Zugriff auf Methoden oder Attribute der Äußeren Klasse hat sie nur, wenn man ihr ein entsprechendes Objekt mit gibt. Alternativ könnte man zwar einfach bei der globalen Symboltabelle beginnen und sich dann bis zum gewünschen Object "durchhangeln", aber das ist ganz schlechter Stil und sollte dringends vermieden werden.
 
Dann werde ich wohl doch Java benutzen müssen, dann ist Python wohl zu billig. Gut, danke für die Antworten!
 
Also ich halte das nicht für billig, sondern korrekt im Sinne der Objektorientierung. Gibt dem inneren Objekt doch einfach im Konstruktor das äußere Objekt mit. Somit weiß der Zauber immer zu welchem Lebewesen er gehört und umgekehrt, das kann auch später von Vorteil sein.

Oder Du lässt das Lebewesen die Sprüche wirken und übergibst beim Wirken das Lebewesen Objekt. Ich sehe an beiden Wegen nichts verwerfliches.

Gibt da verschieden Möglichkeiten der Implementierung, das hängt aber auch von der sonstigen Software Architektur ab.

Ohne bisher auch nur eine Zeile Python geschrieben zu haben, deswegen Python als billig abzutun halte ich für übertrieben.

Ich weiß nicht wie es in Java ist, aber in C# gibt es auch innere Klassen, dennoch müssen die instantiiert werden und wissen auch nicht automatisch zu welchem Objekt sie gehören, nur zu welcher äußeren Klasse, was in Zusammenhang mit Reflection ganz interessant sein kann.

Edit: Auch wenn C# hier nicht Thema ist, zur Vollständigkeit ein kleiner Hinweis: Es steht sogar im C# Handbuch, dass man das Objekt vom äußeren Typ im Konstruktor übergeben soll, wenn vom Objekt des inneren Typs darauf zugrifen möchte: https://docs.microsoft.com/de-de/dotnet/csharp/programming-guide/classes-and-structs/nested-types

Interessant ist an der Stelle auch, wie die Modifier hier wirken bzw. nicht mehr wirken...
 
Zuletzt bearbeitet:
Es liegt natürlich bei dir wie und mit welcher Sprache du entwickelst, aber unabhängig von der Sprache fände ich es unschön das ausüben einer Fähigkeit in der Fähigkeit selbst anzustoßen. Das Lebewesen handelt (aktiv), während die Fähigkeit passiv ist und ausgeübt wird.
 
[...], aber unabhängig von der Sprache fände ich es unschön das ausüben einer Fähigkeit in der Fähigkeit selbst anzustoßen. Das Lebewesen handelt (aktiv), während die Fähigkeit passiv ist und ausgeübt wird.

Genauso sollte es aber gemacht werden, wurde mir beigebracht. So funktioniert die Objektorientierte Denkweise. Wenn du ein Auto programmierst, dann gibst du ihm eine Methode "fahren". Streng genommen kann das Auto garnicht fahren, sondern der Fahrer selbst kann nur fahren. In der objektorientierten Programmierung werden aber die Objekte selbst als die Handelnden aufgefaßt, nicht ihre Benutzer.

Zitat aus dem Buch "Der C++-Programmierer" von Ulrich Breymann.

Julia will Johnny 1000 Euro überweisen. Dem Objekt k1 [gemeint ist damit ein Konto-Objekt] wird also der Auftrag mit den benötigten Daten mitgeteilt:
k1.überweisen(54688490, 1000.00).
Johnny will 22 Euro abheben. Die Aufforderung wird an k2 gesendet: k2.abheben(22).

Es scheint natürlich etwas merkwürdig, wenn einem Konto ein Auftrag gegeben wird. In der objektorientierten Programmierung werden Objekte als Handelnde aufgefasst, die auf die Anforderung selbstständig einen Auftrag ausführen, entfernt vergleichbar einem Sachbearbeiter in einer Firma, der seine eigenen Daten verwaltet und mit anderen Sachbearbeitern kommuniziert, um eine Aufgabe zu lösen.

Also ich halte das nicht für billig, sondern korrekt im Sinne der Objektorientierung. Gibt dem inneren Objekt doch einfach im Konstruktor das äußere Objekt mit. Somit weiß der Zauber immer zu welchem Lebewesen er gehört und umgekehrt, das kann auch später von Vorteil sein.

Wo ist es im Sinne der objektorientierten Programmierung korrekt, das Konzept von inneren Klassen über Board zu werfen? Das ist einfach eine Design-Entscheidung für eine Sprache, würde ich zumindest sagen. Billig klang jetzt vielleicht ein bißchen herabwürdigend. Ich meinte, das Python so entworfen wurde, das es möglichst einfache Programmierung ermöglicht. Das Mitgeben der Objektreferenz ist eine gute Idee. Ich denke, so werde ich das machen!
 
Zuletzt bearbeitet von einem Moderator:
Dexter1997 schrieb:
Genauso sollte es aber gemacht werden, wurde mir beigebracht. So funktioniert die Objektorientierte Denkweise. Wenn du ein Auto programmierst, dann gibst du ihm eine Methode "fahren". Streng genommen kann das Auto garnicht fahren, sondern der Fahrer selbst kann nur fahren. In der objektorientierten Programmierung werden aber die Objekte selbst als die Handelnden aufgefaßt, nicht ihre Benutzer.

Zitat aus dem Buch "Der C++-Programmierer" von Ulrich Breymann.
Um bei dem Beispiel Auto zu bleiben, sollte das keine Methode fahren haben, sondern eher sowas wie GangWechseln und GaspedalBetaetigen mit Parameter % und daraus ermittelt sich dann die Geschwindigkeit, dann passt es doch. Das spiegelt dann doch die reale Interaktion mit dem Auto wieder. Hängt aber auch immer vom Kontext ab.

Evtl. denke ich auch schon zu lange objektorientiert aber ich empfinde das als ziemlich natürlich. Aber auch das Beispiel Konto entspricht doch der Realität. Im analogen Verfahren übergibst Du einen Überweisungsträger an die Bank, also die Parameter. Wie die Bank oder das Konto den Auftrag ausführt weißt Du gar nicht und musst Du auch gar nicht wissen.

Dexter1997 schrieb:
Also ich halte das nicht für billig, sondern korrekt im Sinne der Objektorientierung. Gibt dem inneren Objekt doch einfach im Konstruktor das äußere Objekt mit. Somit weiß der Zauber immer zu welchem Lebewesen er gehört und umgekehrt, das kann auch später von Vorteil sein.

Wo ist es im Sinne der objektorientierten Programmierung korrekt, das Konzept von inneren Klassen über Board zu werfen? Das ist einfach eine Design-Entscheidung für eine Sprache, würde ich zumindest sagen. Billig klang jetzt vielleicht ein bißchen herabwürdigend. Ich meinte, das Python so entworfen wurde, das es möglichst einfache Programmierung ermöglicht. Das Mitgeben der Objektreferenz ist eine gute Idee. Ich denke, so werde ich das machen!

Innere Klassen gibt es doch denke ich? Nur wissen die Klassen nichts von Ihren Objekten, weswegen das Verhalten doch korrekt ist. Und der Lösungsweg mit Übergabe der Objektreferenz im Konstruktur ist doch valide. Evtl sprechen wir auch eifnach aneinander vorbei?! :)
 
Zuletzt bearbeitet:
Dexter1997 schrieb:
Genauso sollte es aber gemacht werden, wurde mir beigebracht. So funktioniert die Objektorientierte Denkweise. Wenn du ein Auto programmierst, dann gibst du ihm eine Methode "fahren". Streng genommen kann das Auto garnicht fahren, sondern der Fahrer selbst kann nur fahren. In der objektorientierten Programmierung werden aber die Objekte selbst als die Handelnden aufgefaßt, nicht ihre Benutzer.
Hier kollidieren Theorie und Praxis. Was du schreibst ist grundsätzlich nicht falsch, allerdings nicht richtig angewendet. Bei dem Auto-Beispiel könnte die Auto-Klasse z.B. ein Motor-Objekt enthalten. Du könntest jetzt dem Motor die Methode fahren geben, aber das wäre kein gutes Design, denn der Motor hat nicht genügend Informationen wie man fährt. Natürlich könnte er auf das übergeordnete Objekt Auto und dann auf darin enthaltene Objekte Getriebe, Lenker, Rad, usw. zugreifen, aber macht es wirklich Sinn das in der Motor-Klasse zu implementieren. Sinnvolle Methode für Motor wären hingegen z.B. anlassen, gas_geben, usw., die dann vom übergeordneten Auto-Objekt genutzt werden können um fahren zu implementieren.
Bei deinem ursprünglichen Beispiel hätte das Lebewesen die Methode faehigkeit_nutzen und das Objekt z.B. die Methode berechne_effektiven_schaden. Das ist eine Frage der Abstraktionsebenen. Bei diesem Beispiel ist es vielleicht ganz so offensichtlich wie beim Auto, aber dennoch eindeutig eine Vermischung zweier Abstraktionsebenen. Das führt dann zu sehr starker Kopplung zwischen Objekten verschiedener Ebenen. Der Abhängigkeitsgraph hat dann statt einer relativ einfachen Baum-Struktur eine komplexere Netz-Struktur. Bei kleineren Projekten ist das in der Regel kein Problem. Wenn die Codebasis aber wächst, verliert man sehr schnell den Überblick wie einzelne Klassen voneinander abhängen und eine kleine Änderung in einer Klasse hat dann plötzlich gewaltige Auswirkungen in einer anderen Klassen, die eigentlich nichts mit der ersten Klasse zu tun hat.

Dexter1997 schrieb:
Zitat aus dem Buch "Der C++-Programmierer" von Ulrich Breymann.
Der Unterschied zwischen diesem Beispiel und deiner Fragestellung ist einfach die, dass das Konto alle notwendigen Daten entweder selbst besitzt oder eben beim Aufruf erhält. Bei dir hat Fähigkeiten nicht alle benötigten Daten und du willst sie auch nicht einzeln als Paramter mitübergeben.

Das Mitgeben der Objektreferenz ist eine gute Idee. Ich denke, so werde ich das machen!
Aus meiner Sicht ist das kaum besser als eine innere Klasse, da auch hier wieder die Fähigkeit-Klasse an die übergeordnete Lebewesen-Klasse gekoppelt wird.
 
Zuletzt bearbeitet:
Verstehe. Die Objektorientierung ist wohl nicht so einfach und durchschaubar, wie immer angepriesen. Nundenn, ich werde mein Projekt erstmal schreiben, und werde es dann auf Codereview veröffentlichen. Dann stelle ich es nochmal in dieses Thema rein und ihr könnt mir dann ja sagen, was ihr davon haltet, oder was ihr anders gemacht hättet.

Ich danke erstmal für alle eure liebevollen Beiträge!
 
Das Grundprinzip ist ja verhältnismäßig einfach, in der Praxis wird es dann aber schon komplizierter. Als ich angefangen habe, hatte ich auch häufig Modelle, die vermeintlich alle "Regeln" der Objektorientierung eingehalten haben, die dann aber im Laufe der Entwicklung in Sackgassen und/oder sehr hässliche Strukturen geführt haben. Mit der Zeit und wachsender Erfahrung wurde das deutlich besser, aber selbst bei sehr erfahrenen Entwicklern passiert es immer mal wieder, dass sie Teile ihres Modells ändern müssen, weil die gewählte Struktur in der Praxis dann doch nicht so gut gepasst hat. Nicht umsonst ist Programmieren nicht nur ein Handwerk, sondern auch eine Kunst.
Ich wünsche dir viel Glück bei deinem Projekt und bin schon gespannt auf das Ergebnis.
 
So ist es Übung macht den Meister und jedes neue Projekt beginnst Du mit immer mehr Erfahrung. Und wichtig ist eben diese zu machen egal in welcher Programmiersprache, Anwenden kannst Du das nachher in jeder Sprache. Die Syntax und Feinheiten einer Sprache sind da eher ein geringes Problem.
 
Es wird nur ein textuelles Rollenspiel, soll aber trotzdem für einen Anfänger ziemlich heftig werden :D
Das Projekt sollte spätestens Ende nächste Woche fertig sein.
 
Zurück
Oben