You can try something like this:
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)
If you need arguments, just use a lambda function. In light of that (and the accepted answer I more recently examined more thoroughly), here's a more complex version with comments, more functionality and examples:
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
Anyway, you can also use the built-in functionality that comes with Tkinter, with such as DoubleVar.trace()
or someWidget.wait_variable()
.
The trace()
method allows you to bind a method to a StringVar, IntVar, FloatVar, DoubleVar, BooleanVar or such variables. Here's a full working Python 3.x example:
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.
"""
You may want to destroy the Tk object at the end of the program. It seems to exit fine without it in my example, however.
wait_variable()
is another alternative that causes the calling function to halt without halting your GUI until a variable you specified changes. There are other similar methods, too.