Wie kann ich die Funktion bei der Wertänderung auslösen?

Ich weiß, diese Frage hat mit Event-Handling zu tun und ich habe über Python Event-Handler ein Dispatcher gelesen, also entweder hat es nicht meine Frage beantwortet oder ich habe die Informationen komplett verpasst.

Ich möchte, dass die Methode m() des Objekts A ausgelöst wird, wenn sich der Wert v ändert:

Zum Beispiel (vorausgesetzt, Geld macht glücklich):

 global_wealth = 0 class Person() def __init__(self): self.wealth = 0 global global_wealth # here is where attribute should be # bound to changes in 'global_wealth' self.happiness = bind_to(global_wealth, how_happy) def how_happy(self, global_wealth): return self.wealth / global_wealth 

Also, wenn der global_wealth Wert geändert wird, sollten alle Instanzen der Klasse Person ihren global_wealth entsprechend ändern.

NB: Ich musste die Frage bearbeiten, da die erste Version schien vorzuschlagen, ich brauchte Getter und Setter Methoden. Entschuldigung für die Verwirrung.

5 Solutions collect form web for “Wie kann ich die Funktion bei der Wertänderung auslösen?”

Sie müssen das Observer Pattern verwenden . Im folgenden Code wird eine Person abonniert, um Updates von der globalen Vermögensentität zu erhalten. Wenn es einen Wechsel zum globalen Reichtum gibt, warnt diese Entität dann alle ihre Abonnenten (Beobachter), dass eine Änderung stattgefunden hat. Person aktualisiert sich dann selbst.

Ich benutze Eigenschaften in diesem Beispiel, aber sie sind nicht notwendig. Eine kleine Warnung: Eigenschaften funktionieren nur auf neue Stilklassen, so dass das (Objekt) nach den Klassendeklarationen zwingend erforderlich ist, um zu arbeiten.

 class GlobalWealth(object): def __init__(self): self._global_wealth = 10.0 self._observers = [] def get_wealth(self): return self._global_wealth def set_wealth(self, value): self._global_wealth = value for callback in self._observers: print 'anouncing change' callback(self._global_wealth) global_wealth = property(get_wealth, set_wealth) def bind_to(self, callback): print 'bound' self._observers.append(callback) class Person(object): def __init__(self, data): self.wealth = 1.0 self.data = data self.data.bind_to(self.update_how_happy) self.happiness = self.wealth / self.data.global_wealth def update_how_happy(self, global_wealth): self.happiness = self.wealth / global_wealth if __name__ == '__main__': data = GlobalWealth() p = Person(data) print p.happiness data.global_wealth = 1.0 print p.happiness 

Was suchst du, heißt (funktionale) reaktive Programmierung . Für Common Lisp gibt es Zellen – siehe Cells Projekt und Cells Manifest und für Python gibt es die Trellis Bibliothek .

Spreadsheets verwenden auch das gleiche Paradigma. Sehr nützlich für die Verfolgung mehrerer zusammenhängender Parameter – wie zB in der GUI-Programmierung.

Die reaktive Programmierung ähnelt dem Observer-Muster, aber mit einer wichtigen Unterscheidung:

Ähnlichkeiten mit Observer-Muster Allerdings würde die Integration der Datenfluss-Konzepte in die Programmiersprache es leichter machen, sie auszudrücken und könnte daher die Granularität des Datenflussgraphen erhöhen. Beispielsweise beschreibt das Beobachtermuster üblicherweise Datenflüsse zwischen ganzen Objekten / Klassen, während die objektorientierte reaktive Programmierung auf die Mitglieder von Objekten / Klassen ausgerichtet sein könnte.

Sie können Eigenschaften verwenden, wenn Sie Code ausführen möchten, wenn Attribute geändert werden. Seien Sie vorsichtig, dass große Nebenwirkungen oder signifikanten Overhead auftreten, wenn ein Attribut geändert wird, ist ein wenig überraschend für jedermann mit Ihrem API, so dass in einigen Fällen Sie wahrscheinlich wollen, um es zu vermeiden, indem Sie Methoden statt.

 class A(object): def m(self, p_value): print p_value @property def p(self): return self._p @p.setter def p(self, value) self._p = value self.m(value) 

Du brauchst eine Immobilie

 class MyClass(object): def __init__(self): self._x = None def x_setter(self, value): self._x = value def x_getter(self): return self._x x = property(x_getter, x_setter) 

Hier wann immer du x MyClass().x = "foo" einstellen willst MyClass().x = "foo" Du benutzt die x_getter-Methode und wann immer du x print MyClass().x ausrufen willst print MyClass().x wird die x_setter-Methode verwenden.

Du kannst so etwas probieren:

 class Variable: def __init__(self, v): self.v=v self.command=None def set(self, v): self.v=v if self.command!=None: self.command() def get(self): return self.v def trace(self, command): self.command=command x=Variable(0) def money(): amount="{:.2f}".format(x.get()) print("You have $"+amount+".") x.trace(money) x.set(5.55) x.set(15.14) 

Wenn Sie Argumente benötigen, verwenden Sie einfach eine Lambda-Funktion. Angesichts dessen (und die akzeptierte Antwort, die ich kürzlich gründlicher untersucht habe), ist hier eine komplexere Version mit Kommentaren, mehr Funktionalität und Beispielen:

 class Variable: #This is a class for the variable you want to bind something to def __init__(self, v): self.v=v self.commands=[] def set(self, v): #Set the variable's value and call any bound functions self.v=v for x in self.commands: x() def get(self): #Get the variable's value return self.v def trace(self, *commands): #Bind one or more functions to the variable for x in commands: if x in self.commands: raise ValueError("You can't add the same command object twice. If you need to, use another lambda function that calls the same function with the same parameters.") self.commands.extend(commands) def untrace(self, *commands): #Unbind one or more functions from the variable for x in commands: if x not in self.commands: raise ValueError(str(x)+" is not a traced command.") for x in commands: if x in self.commands: self.commands.remove(x) def clear_traces(self): #Removes all functions bound to the variable self.commands.clear() x=Variable(0) #Make the variable, starting with a value of 0 def money(name): #Define the method to bind amount="{:.2f}".format(x.get()) print(name+" has $"+amount+".") sam=lambda : money("Sam") #We're making a new method to bind that calls the old one with the argument "Sam" sally=lambda : money("Sally") #Another one (Sally and Sam will always have the same amount of money while they are both bound to the variable.) #Bind them both to the value (not that this is practical, but we're doing both for demonstration) x.trace(sam) x.trace(sally) #Set the value x.set(5.55) #Unbind the sam lambda function and set the value again x.untrace(sam) x.set(15.14) """ This prints the following: > Sam has $5.55. > Sally has $5.55. > Sally has $15.14. """ 

Alternative

Wie auch immer, du kannst auch die eingebaute Funktionalität verwenden, die mit Tkinter kommt, mit DoubleVar.trace() oder someWidget.wait_variable() .

Mit der Methode trace() können Sie eine Methode an einen StringVar, IntVar, FloatVar, DoubleVar, BooleanVar oder solche Variablen binden. Hier ist ein volles Python 3.x Beispiel:

 from tkinter import * tk=Tk() tk.withdraw() d=DoubleVar(master=tk, value=0) def my_event_handler(*args): amount="{:.2f}".format(d.get()) print("$"+amount) d.trace(mode="w", callback=my_event_handler) d.set(5.55) d.set(15.12) """ This prints the following: > You have $5.55. > You have $15.12. """ 

Sie können das Tk-Objekt am Ende des Programms zerstören. Es scheint aber in meinem Beispiel gut zu gehen.

wait_variable() ist eine weitere Alternative, die dazu führt, dass die wait_variable() , ohne die GUI wait_variable() bis eine Variable, die Sie spezifiziert haben, sich ändert. Es gibt auch andere ähnliche Methoden.

Python ist die beste Programmiersprache der Welt.