Update von Attribut in 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
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hi Leute,

ich habe eine Klasse mit attributen definiert. Diese Attribute werden im Programmablauf zugewiesen. Nun möchte ich weitere Attribute aus den ursprünglichen berechnen.
Momentan realisiere ich das über die "@property" Funktionalität:

Code: Alles auswählen

class test:
    def __init__(self):
        self.x = 0.0
    @property
    def y(self):
        return self.x**2.0
a = test()
a.x  = 2.0
print a.y
Leider wird jedes mal wenn ich aufrufe die Berechnung ansich durchgeführt. In meinem eigentlichen Code ist diese Berechnung sehr viel aufwändiger und muss sehr oft ausgeführt werden.
Gibt es eine Möglichkeit nach dem alle Attribute der "__init__"-Sektion zugewiesen wurden eine Art "update" durchzuführen und den Wert y der Klasse abzuspeichern, so dass nicht immer die Berechnung erfolgen muss?
Meine Vorstellung wäre:

Code: Alles auswählen

class test:
    def __init__(self):
        self.x = 0.0
    def update(self):
        self.y = self.x**2.0
        return  # irgendwie muss man hier etwas anderes gemacht werden
a = test()
a.x  = 2.0
a.update()
print a.y
BlackJack

@schneitzmaster: Du könntest `x` zum Property machen und `y` immer neu berechnen wenn `x` ein anderer Wert zugewiesen wird. Oder beides als Property, beim Zuweisen an `x` wird ein ”dirty”-Flag gesetzt und beim Abfragen von `y` wird entweder ein gecacheter Wert geliefert wenn das Flag nicht gesetzt ist, oder eben neu berechnet.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Im Endeffekt bleibt Dir wenig übrig, als ein Attribut einzuführen, welches das Ergebnis hält. Dieses kannst Du dann über die Property zurückgeben. Per Konvention sind alle Methoden und Attribute, die mit einem Unterstrich beginnen, als Implementierungsdetails zu sehen, d.h. diese sollen von extern idR. *nicht* direkt benutzt werden. Du könntest also sowohl die Berechnung, als auch das Attribut selber damit ausstatten und dann über eine Property zugänglich machen. Alternativ kannst Du die Berechnung auch in die Property packen und dann über das interne Attribut prüfen, ob diese erneut durchgeführt werden muss, oder man den bereits berechneten Wert einfach zurückgeben kann.

Das wären wohl die einfachsten Optionen!

Sicherlich gibt es sonst noch (aufwendigere) Möglichkeiten über eine externe Klasse, die einmal berechnet und dann nur noch den Zustand zurück liefert oder eine Closure... aber: wieso sollte man sich das so kompliziert machen? ;-)

Edit: Ok, BlackJack ist auch Frühaufsteher und hatte noch einen anderen Ansatz - daher lasse ich das mal so stehen :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hi danke für die Tips.
Ich habe jetzt folgende Lösung:

Code: Alles auswählen

class test:
    def __init__(self):
        self.x = 0.0
        self.y = 0.0
    def update(self):
        self.y = self.x**2.0
        return
a = test()
a.x  = 2.0
print a.y
a.update()
print a.y
Allerdings muss ich jedes mal die update Funktion ausführen. Von daher finde ich Blackjacks Variante reizvoll.
Allerdings weiß ich nicht genau wie das gemeint ist.
Könntest du ein Beispiel geben?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Ein Beispiel könnte wie folgt aussehen

Code: Alles auswählen

from time import sleep

class Worker():
    def __init__(self):
        self._x = 0
        self._y = None

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value
        self._y = None

    @property
    def y(self):
        if self._y is None:
            sleep(2)
            self._y = self._x + 42
        return self._y


thing = Worker()
thing.x = 13
print(thing.y)
print(thing.y)
thing.x = 23
print(thing.y)
print(thing.y)
Wenn x gesetzt wird, wird damit automatisch der Wert für y (bzw. _y) auf None gesetzt. Das wiederum wird beim Abruf von y abgefragt, so dass der Wert bei Bedarf neu berechnet werden kann.
Antworten