Datenweitergabe zwischen Instanzen durch Vererbung?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hallo Leute,
langsam verstehe ich das Konzept der OOP und ihre Anwendung in Python, nicht zu letzt durch die Hilfe in diese Forum.
Leider habe ich noch ein Verständnisproblem mit der Vererbung.
Ich habe 2 Klassen wobei in der Hauptklasse main_class eine Instanz der Unterklasse integriert ist.
Nun möchte ich von dieser Unterklasse auf Attribute der Hauptklasse zugreifen. Ist das überhaupt möglich?
Hier mein Versuch das in Python zu realisieren:

Code: Alles auswählen

class main_class(object):
    def __init__(self, var1=1.0, var2=2.0):
        self.var1 = var1
        self.var2 = var2
        self.sub_class = sub_class()
    @property    
    def var3(self):
        return self.var1 * self.var2

class sub_class(main_class):
    def __init__(self):
        self.var4 = 5.0
    @property
    def var5(self,main_class):
        return main_class.var3 + self.var4 


test = main_class()

test.sub_class.var5
Ich möchte das var5 welche in der sub_class eingeführt wird, mit Attributen aus der main_class berechnen.
Sirius3
User
Beiträge: 18300
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo schneitzmaster,

Vererbung heißt, dass die Kindklasse alle Attribute der Elternklasse erbt.
Du brauchst also keinen Verweis auf main_class, es reicht self.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hi Sirius3,
wenn ich das so durch führe gelingt aber nicht mal mehr das Zuweisen der Instanz test

Code: Alles auswählen

class main_class(object):
    def __init__(self, var1=1.0, var2=2.0):
        self.var1 = var1
        self.var2 = var2
        self.sub_class = sub_class(main_class)
    @property    
    def var3(self):
        return self.var1 * self.var2

class sub_class():
    def __init__(self):
        self.var4 = 5.0
    @property
    def var5(self):
        return self.var3 + self.var4 


test = main_class()
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

schneitzmaster hat geschrieben:wenn ich das so durch führe gelingt aber nicht mal mehr das Zuweisen der Instanz test
Du richtest ja auch experimentell heilloses Durcheinander im Code an ohne wirklich durchdrungen zu haben was da passiert.

Bitte achte bei den Code-Beispielen darauf wo die Klasse und wo eine Instanz verwendet wird.

Code: Alles auswählen

class Base_Class(object):
    def __init__(self):
        self.a = 42

class Sub_Class(Base_Class):
    def __init__(self):
        super(Sub_Class, self).__init__() # Konstruktor der Basisklasse aufrufen
        self.b = 23

foo = Sub_Class()
print(foo.a)
Was du hier hast ist Vererbung. Die Klasse Sub_Class erbt alle Attribute und Methoden von Main_Class und hat daher auch ein Attribut a.

Du wirfst das aktuell damit durcheinander, dass du einer Instanz der Klasse Main_Class ein Attribut geben möchtest das eine Instanz vom Typ Sub_Class enthält. Das kannst du aber auch problemlos ohne Vererbung hinbekommen.

Code: Alles auswählen

class Main_Class(object):
    def __init__(self):
        self.a = Other_Class()

class Other_Class(object):
    def __init__(self):
        self.b = 23

foo = Main_Class()
print(foo.a.b)
Hier hat foo, also die Instanz von Main_Class, kein Attribut b. foo hat aber ein Attribut a, das eine Instanz von Other_Class ist. a selber verfügt nun wiederum über ein Attribut b.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Ja das ist mir schon klar.
Ich hatte bloß das Code-Fragment noch einmal gepostet weil ich nicht wußte wie Sirius3 das meint mit dem self um mein Problem zu lösen.
Ich bin mir auch nicht sicher, ob ich mein Problem mit Vererbung lösen kann.
Daher noch mal meine eigentliche Frage:

Gibt es eine Möglichkeit von der Sub_Class auf Attribute der Base_Class zuzugreifen (siehe erster Post) ?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Das naechste Mal poste doch bitte auch die Fehlermeldung.

Die wird wohl eher so ausgesehen haben, dass du 2 Argumente uebergeben hast, aber nur eines erwartet wurde, schliesslich uebergibst du `sub_class` ein Argument, obwohl es keines erwartet.

Zu guter Letzt: Tu dir einen Gefallen und benutze PEP8 (oder eine sonstige Konvention, die dir hilft Klassen, Methoden, usw. auseinanderzuhalten) und arbeite das Tutorial durch.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

schneitzmaster hat geschrieben:Gibt es eine Möglichkeit von der Sub_Class auf Attribute der Base_Class zuzugreifen (siehe erster Post) ?
Ja, auch ohne Vererbung: Uebergib `Sub_Class` das Exemplar von `Base_Class`:

Code: Alles auswählen

class Base_Class(object):
    def __init__(self):
        ...
        self.sub = Sub_Class(self)

class Sub_Class(object):
    def __init__(self, base):
        ...
        self.base = base
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

schneitzmaster hat geschrieben:Ich möchte das var5 welche in der sub_class eingeführt wird, mit Attributen aus der main_class berechnen.
Nach der Erklärung im vorherigen Posting hier mal eine Variante die sich an deinem Code orientiert.

Code: Alles auswählen

class Base(object):
    def __init__(self):
        self.a = 2
        self.b = 3
    @property
    def c(self):
        return self.a * self.b

class Child(Base):
    def __init__(self):
        super(Child, self).__init__()
        self.d = 4
    @property
    def e(self):
        return self.c + self.d

test = Child()
# print(dir(test))
print(test.e)
Kommentiere mal das print(dir(test)) wieder ein. Du siehst dann eine Liste der Attribute und Methoden von test.
BlackJack

@schneitzmaster: Welches Problem willst Du durch Vererbung denn lösen? Vererbung ist für „ist-ein(e)”-Betziehung gedacht. Also der Satz „`Unterklasse` ist ein `Oberklasse`” sollte Sinn machen. Beispiel: „Ein `Auto` ist ein `Fahrzeug`”. Gegenbeispiel: „`Kunde` ist ein `Konto`” — das macht keinen Sinn und sollte nicht über Vererbung gelöst werden.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Anscheinend kann ich mein Problem nicht durch Vererbung lösen.
Der Ansatz von /me trifft leider auch noch nicht den Kern meines Anliegens.

Ich probier das Ganze noch mal an einem anschaulicherem fiktivem Beispiel zu demonstrieren.
Ich habe ein Auto welches die Hauptklasse ist. Das Auto hat die Eigenschaft Gewicht M und Gravitation g in der es sich befindet. Auf das gesamte Auto wirkt die Gewichtskraft F = m*g.
Jedes Auto hat weiterhin Federn (das soll die Unterklasse sein) mit der Gesamtfedersteifigkeit c.
Diese werden nun aufgrund der wirkenden Gewichtskraft F entsprechend um deltaX zusammengedrückt. Dieses deltaX bestimme ich mir aus deltaX = F/c.
Dieses möchte ich wie folgt aufrufen: Auto.Feder.deltaX

Code: Alles auswählen

class Auto(object):
    def __init__(self):
        self.M = 2000.0
        self.g = 9.81
        self.Feder = Feder()
    @property
    def F(self):
        return self.M * self.g

class Feder(Auto):
    def __init__(self):
        self.C = 100.0
    @property
    def deltaX(self):
        return Auto.F/self.C

Trabi = Auto()

print (Trabi.Feder.deltaX)
Ich hoffe mein Problem ist jetzt etwas klarer. Geht eine solche Vorgehensweise (das Beispiel ist trivial und soll nur exemplarisch sein, ich hätte ja auch alles in eine Klasse schreiben können).
Mir ist klar das mein Code nicht funktioniert, da Feder ja erbt aber nicht auf die "höhere" Instanz zugreifen kann. Ich habe aber keine andere Idee/Ansatz wie ich das sonst lösen könnte.
BlackJack

@schneitzmaster: Du hast da schon wieder beides vermischt: Vererbung *und* Komposition. Die Vererbung ist Unsinn: Eine Feder ist kein Auto. Ein Auto *hat* eine (oder mehr) Federn. Also ist sind die Federn Attribute von Autos.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

okay ja da ist mir bewußt, ich hatte ja geschrieben das ich mir nicht besser zu helfen weiß meine Vorstellungen umzusetzen.
Fakt ist, dass das Auto das Attribut Feder hat und die Feder (ich meine hier Gesamtfedersteifigkeit) wieder das Attribut deltaX.

Demnach muss der Zugriff auf deltaX meiner Meinung nach über
Auto.Feder.deltaX
erfolgen, oder?

Ist das mit dem von mir gewünschten "internen" Berechnungen (erst Gewichtskraft und dann Federgesetz) möglich?
Benutzeravatar
pillmuncher
User
Beiträge: 1531
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@schneitzmaster: Du musst dir den Unterschied zwischen Klassen und Exemplaren (auch Instanzen genannt) der Klassen klarmachen. Nehmen wir zB. die Klasse Zahlungsmittel. Es gibt viele Exemplare von Zahlungsmitteln (Euro, Dollar, Yen, ...) die alle gewisse Eigenschaften gemein haben: Sie können gegen Güter getauscht werden. Sie können ineinander gewechselt werden. Sie bestehen aus Papier oder Metall oder Buchungseinträgen in einem Konto. Sie bezeichnen Preise von Gütern. Auf die Frage "Wieviel kostet das?" wäre eine sinnvolle Antwort zB. "2 Euro 98", aber nicht "Zahlungsmittel!".

Auf dein Beispiel übertragen: ein Auto hat als Bestandteile zwar ein oder mehrere Federn, aber nicht die Klasse Feder. Es wäre völlig sinnlos zu sagen "mein Auto besteht aus Metall, Kunstoff, Gummi, Glas, Benzin, Schmieröl und dem abstrakten Konzept der Federung. Wenn das Benzin ausgeht, kann ich in der Tankstelle neues kaufen, und wenn die Federung ausgeht kaufe ich sie im Geschäft für abstrakte Konzepte, wo ich auch Summen, Liebe, Gerechtigkeit und das Konzept des Abstrakten Konzepts kaufen kann".

In der Art der Objektorietierung, wie sie Python verwendet, stellen Klassen insofern Konzepte dar, als sie berschreiben, welche Eigenschaften ihre Exemplare haben. Ein Exemplar der Klasse Feder hat dann zB. eine gewisse Federsteifigkeit, Größe, Gewicht, etc,. je nachdem welche dieser Eigenschaften der Programmierer zur Lösung seines Problems für wichtig erachtet.

Die Klasse Auto beschreibt, welche Eigenschaften alle Autos innerhalb des Programms haben sollen: Preis, Farbe, Gewicht, aber auch zB. Federn, dh. Exemplare der Klasse Feder, nicht die Klasse Feder selbst:

Code: Alles auswählen

class Feder(object):
    def __init__(self, steifigkeit):
        self.steifigkeit = steifigkeit
    # usw

class Auto(object):
    def __init__(self):
        self.feder1 = Feder(20)
        self.feder2 = Feder(30)
    # usw

a = Auto()
print a.feder1.steifigkeit  # 20
print a.feder2.steifigkeit  # 30
Ein Auto hat Federn, und eine Feder hat Steifigkeit, aber ein Auto ist keine Feder, und eine Feder ist kein Auto und ein Auto hat nicht als Bestandteil das abstrakte Konzept der Federung, sondern eine Konkretion dieses Konzepts in Form von konkreten Federn.
In specifications, Murphy's Law supersedes Ohm's.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hi pillmuncher,
vielen vielen Dank für deinen ausführlichen Kommentar!
Mit deinem Programmierbeispiel habe ich jetzt die von mir gewünschte Funktionalität realisieren können.
Ich denke das ich deine Erklärungen verstanden habe, ich wusst nur nicht wie ich mein Problem umsetzen konnte.
Der einfache Weg läuft dann schlussendlich über die Variablenübergabe bei den Klassen als das was in den Klammern steht. Das war mir noch nicht so ganz bewusst.
Meine Lösung sieht wie folgt aus:

Code: Alles auswählen

class Feder(object):
    def __init__(self, F):
        self.F = F
        self.steifigkeit = 100.0        
    @property
    def deltaX(self):
        return self.F/self.steifigkeit

class Auto(object):
    def __init__(self):            
        self.M = 2000.0
        self.g = 9.81    
        self.feder1 = Feder(self.F)
    @property
    def F(self):
        return self.M*self.g
        
a = Auto()
print a.feder1.steifigkeit  # 20
print a.feder1.deltaX
a.feder1.steifigkeit = 200.0
print a.feder1.deltaX
Wichtig ist dabei nur die Reihenfolge wie man self.M self.g und self.feder1 = Feder(self.F) definiert, was wohl daran liegt das für die Berechnung von self.F ja self.M und self.g notwendig sind.
Ich hoffe mal das mein Code so stimmt und nicht nur "zufällig" das rauskommt was soll.
Vielleicht könnte das ja noch mal jemand bestätigen.
Danke noch mal!
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

schneitzmaster hat geschrieben:Wichtig ist dabei nur die Reihenfolge wie man self.M self.g und self.feder1 = Feder(self.F) definiert, ...
Aus diesem Grund und auch, weil sich die Masse des Autos ändern kann (Sprit, Passagier, Gepäck etc.) würde ich der Klasse Auto noch eine Methode zum Ändern/Setzen der Masse und der Klasse Feder eine Methode zum Ändern von 'F' spendieren. Diese beiden Methoden können dann miteinander Kommunzieren, falls sich Werte ändern.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hi mutetella,
das sind gute Vorschläge aber wie setzte ich so etwas um?
Ich habe es erfolglos mit getter und setter des property objects probiert ( http://docs.python.org/2/library/functi ... l#property )

Code: Alles auswählen

class Feder(object):
    def __init__(self, F):
        self.F = F
        self.steifigkeit = 100.0        
    @property
    def deltaX(self):
        return self.F/self.steifigkeit
  
class Auto(object):
    def __init__(self):            
        self._M = 2000.0
        self.g = 9.81    
        self.feder1 = Feder(self.F)
    @property
    def M(self):
        return self._M        
    @M.setter
    def M(self,value):
        self._M = value            
    @property
    def F(self):
        return self.M*self.g
        
a = Auto()
print a.feder1.deltaX           # 196.2
a.feder1.steifigkeit = 200.0
print a.feder1.deltaX           #   98.1
a.M = 1000.0
print a.feder1.deltaX           # 98.1
Leider klappt das ganze nicht bei der Feder. Könntest du mir da noch mal auf die Sprünge helfen?
BlackJack

@schneitzmaster: `Auto.M` als `property()` ist hier irgendwie sinnfrei. Wenn man in den Methoden nichts mit dem Wert macht ausser ihn einem Attribut zuzuweisen beziehungsweise abzufragen, hat man doch vom Effekt keinen Unterschied zu einem ganz normalen Attribut.

Du müsstest der `Feder` wohl statt dem `F`-Wert das `Auto`-Exemplar mitgeben und bei `deltaX()` dann denn *aktuellen* `F`-Wert vom Auto abfragen.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Ja genau und wie kann ich das Auto-Exemplar mitgeben? Das habe ich ja die ganze Zeit in den Posts vorher mit der Vererbung versucht. Klappt aber nicht Vererbung ja etwas komplett anderes ist.
Welcher Befehl oder welches Python-spezifische Schlüsselwort, über das ich mich im Netz informieren kann, gibt es da?
BlackJack

@schneitzmaster: Dazu brauchst Du weder einen Befehl noch ein Python-spezifisches Schlüsselwort. Du musst einfach nur das `Auto`-Exemplar übergeben. Also statt dem `F`-Attribut vom `Auto`-Exemplar das `Auto`-Exemplar *selbst*. Falls das jetzt als Info nicht reicht, solltest Du den letzten Satz mal auf Englisch übersetzen. Und/oder Dir überlegen welche Namen Dir in der `Auto.__init__()` lokal zur Verfügung stehen (Spoiler: es ist ja nur einer) und welchen Typ die darab gebundenen Objekte haben.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Okay jetzt hab ich's gerafft.

Code: Alles auswählen

lass Feder(object):
    def __init__(self, auto):
        self.auto = auto
        self.steifigkeit = 100.0        
    @property
    def deltaX(self):
        _F = self.auto.F        
        return _F/self.steifigkeit
  
class Auto(object):
    def __init__(self):            
        self.M = 2000.0
        self.g = 9.81    
        self.feder1 = Feder(self)       
    @property
    def F(self):
        return self.M*self.g
        
a = Auto()
print a.feder1.deltaX           # 196.2
a.feder1.steifigkeit = 200.0
print a.feder1.deltaX           #   98.1
a.M = 1000.0
print a.feder1.deltaX
Aber könnte man das nicht irgendwie eleganter lösen mit der Methode die mutetella vorgeschlagen. Denn so muss ich mir ja lokal in "Feder" erst alle Variablen aus auto neu definieren oder über einen länglichen Befehel (self.auto.F) darauf zugreifen, so dass komplizierte Formeln schnell unlesbar werden.
Leider weiß ich nicht genau wie er das mit den Methoden zum setzen und ändern gemeint hat.
Antworten