Seite 1 von 1

Dynamische Initialisierung einer Klasse

Verfasst: Dienstag 6. März 2018, 01:48
von brave
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

Re: Dynamische Initialisierung einer Klasse

Verfasst: Dienstag 6. März 2018, 07:43
von noisefloor
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

Re: Dynamische Initialisierung einer Klasse

Verfasst: Dienstag 6. März 2018, 07:54
von __deets__
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.

Re: Dynamische Initialisierung einer Klasse

Verfasst: Dienstag 6. März 2018, 08:15
von Sirius3
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: ...`

Re: Dynamische Initialisierung einer Klasse

Verfasst: Dienstag 6. März 2018, 11:32
von bwbg
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.

Re: Dynamische Initialisierung einer Klasse

Verfasst: Sonntag 11. März 2018, 00:16
von brave
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.

Re: Dynamische Initialisierung einer Klasse

Verfasst: Sonntag 11. März 2018, 13:27
von Sirius3
@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)