Dynamische Initialisierung einer Klasse

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.
Antworten
brave
User
Beiträge: 24
Registriert: Mittwoch 24. Februar 2016, 18:30

Hallo Leute,

Ich möchte gerne eine Klasse dynamisch initialisieren.
Es gibt 5 Init Variablen, nennen wir sie a,b,c,d,e von denen ich zwei auswähle aus denen ich dann jeweils die anderen 3 errechnen kann.
Ich könnte das so machen:

Code: Alles auswählen

class Dynamic:
    def __init__(self, a=None, b=None, c=None, d=None, e=None):
        # Wenn a, b gegeben ..
        self.a =  a
        self.b = b
        self.c = (self.e*self.a)**0.5
        self.d = self.a/self.c
        self.e = self.c**2/self.a
        
        # Wenn c, d gegeben ...
        self.a =  const*self.b/const
        self.b = self.a*const
        self.c = c
        self.d = d
        self.e = c**2/self.a
        
        # Wenn e, a gegeben ...
        self.a =  a
        self.b = a*const
        self.c = (e*a)**0.5
        self.d = a/self.c
        self.e = e
        
        ...
        

if __name__ == '__main__':
    obj1 = Dynamic(a, b)
    obj2 = Dynamic(c, d)
    obj3 = Dynamic(e, a)
    ...    
Aber ich müßte dann für jede der 10 möglichen Kombinationen den Formelblock neu hinschreiben.
Geht das irgendwie intelligenter?

Danke und Gruß
brave
Benutzeravatar
noisefloor
User
Beiträge: 3853
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

um das Schreiben der Formeln wirst du nicht umhinkommen. Allerdings würde ich die fehlenden Atttribute nicht automatisch berechnen lassen, sondern eine Methode wie `calculate_missing_attribute` schreiben, die explizit aufgerufen werden muss.

Gruß, noisefloor
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also aktuell hast du da ein paar dicke Fehler drin. Zum einen rufst du die Klassen IMMER mit a, b auf. Nur weil deine Variablen auf aufrufseite c und d heißen, ändert der Konstruktor nicht magisch seine Argumentreihenfolge. Da musst du schon explizit Keyword-Argumente verwenden.

Und im zweiten Fall hast du c & d gegeben, und berechnest a und b aus jeweils b und a - das geht ja auch in die Hose.

Um die fallunterscheidung kommst du *vielleicht* rum, indem du properties verwendest. In denen kannst du dann explizit prüfen „ist X da, dann zurück geben, sonst berechnen aus”. Ob das klappt musst du mal ausprobieren.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Um das von Hand rechnen zu sparen, kannst Du sympy verwenden, um Dein Gleichungssystem nach den fehlenden Variablen dynamisch auflösen zu lassen. Sonst würde ich umgekehrt vorgehen und Abfragen `if a is None: ...`
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Da sich die Attribute c, d, e aus a und b herleiten lassen, können diese als properties angelegt werden. Somit käme __init__ mit a und b aus.

Für die alternativen Initialisierungen/Konstruktionen böten sich Klassenmethoden an.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
brave
User
Beiträge: 24
Registriert: Mittwoch 24. Februar 2016, 18:30

Es ist doch komplizierter weil doch kein LGS und ich komme um abfragen nicht herum. Aber auch mit Sympy müsste ich ja fragen, is x und y da, wenn ja dann evaluiere nach z usw.

Grundsätzlich:
Warum soll man Attribute nicht direkt berechnen sondern über properties gehen?
Der einzige Vorteil ist, dass der Anwender der Klasse ein Property nicht versehenlich überschreiben kann, wenn kein setter gesetzt ist oder?

Zusatzfrage:
Wird ein property-Attribut einmalig beim erstellen eines Objektes berechnet oder jedesmal wieder, wenn es benutzt wird?
Wenn zweiteres, wäre das ja eher ein Grund die nicht zu benutzen.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@brave: wer spricht hier von linearen Gleichungssystemen? Deine Formeln können nicht stimmen, weil man aus ihnen nicht alle Variablen berechnen kann.

Hier mal ein Beispiel:

Code: Alles auswählen

class Dynamic:
    def __init__(self, a=sympy.Symbol('a'), b=sympy.Symbol('b'), c=sympy.Symbol('c'), d=sympy.Symbol('d'), e=sympy.Symbol('e')):
        result = sympy.solve([(b*a)**0.5-c, a/c - d, c**2/a-e])
        self.a = result.get('a', a)
        self.b = result.get('b', b)
        self.c = result.get('c', c)
        self.d = result.get('d', d)
        self.e = result.get('e', e)
Antworten