I have a function which creates some labels and input fields and a button. I want the button's command function manage objects from this function. Can I do this without making variables global?
Here's the code:
def add_clicked():
cuspsInfo.append((int(xInput.get()), int(yInput.get()), indexInput.get()))
xInput.delete(0, END)
yInput.delete(0, END)
indexInput.delete(0, END)
def startup_menu():
global cuspsInfo
cuspsInfo = []
global label
label = Label(window, text="Add a cusp:", font=("Arial", 20, "bold"),
fg=SECOND_COLOR, bg=FIRST_COLOR)
label.place(relx=0.5, rely=0.3, anchor=CENTER)
global xInput
global yInput
global indexInput
xInput = Entry(window)
xInput.place(relx=0.52, rely=0.4, anchor=CENTER)
yInput = Entry(window)
yInput.place(relx=0.52, rely=0.45, anchor=CENTER)
indexInput = Entry(window)
indexInput.place(relx=0.52, rely=0.5, anchor=CENTER)
global xLabel
global yLabel
global indexLabel
xLabel = Label(window, text="x(0-500):", font=(
"Arial", 20, "bold"), fg=SECOND_COLOR, bg=FIRST_COLOR)
xLabel.place(relx=0.34, rely=0.4, anchor=CENTER)
yLabel = Label(window, text="y(0-500):", font=(
"Arial", 20, "bold"), fg=SECOND_COLOR, bg=FIRST_COLOR)
yLabel.place(relx=0.34, rely=0.45, anchor=CENTER)
indexLabel = Label(window, text="name:", font=(
"Arial", 20, "bold"), fg=SECOND_COLOR, bg=FIRST_COLOR)
indexLabel.place(relx=0.36, rely=0.5, anchor=CENTER)
global addButton
global runButton
addButton = Button(window, text="add", command=add_clicked)
addButton.place(relx=0.45, rely=0.6, anchor=CENTER)
runButton = Button(window, text="run", command=run_clicked)
runButton.place(relx=0.55, rely=0.6, anchor=CENTER)
I'd "partially apply" the function. First, change your callback to accept four arguments:
def add_clicked(x_in, y_in, index_input, cusps_info):
cusps_info.append((int(x_in.get()), int(y_in.get()), index_input.get()))
x_in.delete(0, END)
y_in.delete(0, END)
index_input.delete(0, END)
Now, wrap the call to that callback in another function, and supply the arguments then. This can be does with a simple lambda
:
addButton = Button(window, text="add", command=lambda: add_clicked(xInput, yInput, indexInput, cuspsInfo))
or with functools.partial
:
from functools import partial
addButton = Button(window, text="add", command=partial(add_clicked, xInput, yInput, indexInput, cuspsInfo))
Both have the same effect: the arguments are "pre-supplied" so that the callback can later be called without any arguments.
As you can see though, as the amount of arguments increases, this becomes increasingly messy. This technique is best for smaller numbers of arguments. If you have a lot of data needing to be passed into a function, it may make sense to place them into a NamedTuple
or a full custom class (if they're all very similar and make sense together).