Python lambda seems to be binding the last used variable values every time [duplicate] - python

This question already has answers here:
Using lambda expression to connect slots in pyqt
(4 answers)
Unable to send signal from Button created in Python loop
(1 answer)
Differences between lambda and partial when connecting clicked signal in PyQt/PySide
(3 answers)
Closed yesterday.
I'm trying to associate key-value pairs with buttons in PyQt5.
Python seems to think that I want the last value in my list for all of my button connect methods.
for i in range(len(myList)):
myKey = myList[i]
print(myKey)
x = baseX + (counter % 4) * 220
btn = QPushButton(w)
btn.setText(myKey[0])
btn.resize(200, 30)
btn.move(x, y)
if counter % 4 == 3:
y = y + 40
btn.clicked.connect(lambda a=myKey[0], b=myKey[1]: printMyKeyValuePair(a, b))
btn.show()
counter += 1
This always prints the key-value pair that is last in my list regardless of which button I click.
I've tried it a hundred different ways with copy, deepcopy, declaring variables in the lambda, directly referencing the variables from the loop. The intent is supposed to be that when a button is clicked it prints the key-value pair associated with that button.

Related

On clicking the numbers to input it onto the entry widget, it always adds 10 rather than the number supposed to [duplicate]

This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
Closed 11 months ago.
for i in range(1,4):
for j in range(3):
button = tk.Button(text=str(num+1),master=window,padx=40,pady=20,command=lambda:button_click(num+1))
button.grid(row=i,column=j)
num+=1
def button_click(Number):
ent_number.insert(tk.END,Number)
Whenever I click any button, which shows the appropriate numbers i.e 1,2,3,etc. it always inserts 10 to the entry widget.
You can easily solve your problem by making num a default parameter:
lambda num=num: button_click(num)
Why does this work?
A pre-defined variable in a function could either be a parameter or a global variable. The first preference goes to the function parameter.
For example, if you execute the below code, it will print out 10, not 6.
def func(num):
print(num)
num = 6
func(10)
In your code, when you use lambda:button_click(num+1), num is considered a global variable and the value of num is always 10 irrespective of which button triggered the event.
However, when num is passed as a parameter, the parametric value doesn't change with iterations of the loop. When the function is executed, the parametric value of num is considered, which depends on the source button.

PyQt5 clicked button created in loop [duplicate]

This question already has answers here:
lambda in for loop only takes last value [duplicate]
(3 answers)
Closed 1 year ago.
im trying to make calculator in pyqt5 and I cannot correctly pass numbers to function when button is clicked.
This is my code:
buttons = ['7','8','9','/','MOD','AND','4','5','6','*','Or','Xor','1','2','3','.','Lsh','Not','0','+/-',',','+','=','Int','A','B','C','D','E','F']
positions = [(i,j) for i in range(5) for j in range(6) ]
#creating array of buttons
self.gridButtons = [[0 for x in range(6)] for y in range(5)]
for position, button in zip(positions,buttons):
if button.isnumeric():
print(button)
self.gridButtons[position[0]] [position[1]] = QPushButton(button, clicked = lambda:self.numberPressed(button))
Problem is when I press the button, it triggers a function but instead of passing appropriate string like '1','2', it passes the last string in buttons array which is 'F'. How can I overcome this?
Your lambda is executed at some time after your loop has run completely. This means that the lambda will always be executed with the last object of the for loop.
To prevent this from happening, you can use a closure. Python has a simple way to create closures: Instead of a lambda use functools.partial
self.gridButtons[position[0]] [position[1]] = QPushButton(button, clicked = functools.partial(self.numberPressed, button))

python - tkinter command = lambda late binding issue in nested for loop [duplicate]

This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
Closed 6 months ago.
I'm trying to make multiple buttons in double for loop. I couldn't find the syntax about this problem.
for i in range(row):
for j in range(col):
b = tk.Button(new_root,command = lambda i=i : test1(i,j))
b.place(x = (j*30), y = (i*30))
I understood that part using i=i to avoid late binding issue for i, but what should I do for j? the other iterator??
thank you so much in advance,
You have to give both variable to lambda function:
lambda i=i, j=j: test1(i,j)

How do I make different variables in for loops In Python [duplicate]

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 3 years ago.
I am making a program that has a for loop and every time the loop is ran I want it to make a new variable like
for item in range(0, size)
(Make new variable bit1, bit2, bit3, bit4, etc with value of 0)
Is this possible?
Create a List of variables and append to it like this:
bits = []
for item in range(0, size)
bits.append(0)
# now you have bits[0], bits[1], bits[2], etc, all set to 0
We can do this by appending to the vars() dictionary in the program.
for index, item in enumerate(range(size)):
vars()[f'bit{index+1}'] = 0
Try calling the names now:
>>> bit1
0
And while this works, I'd recommend using a list or a dict instead.

Explain this particular python lambda expression [duplicate]

This question already has answers here:
Accessing elements of Python dictionary by index
(11 answers)
Closed 4 years ago.
Iam trying to learn lambda expressions and came across the below :
funcs = {
idx: lambda: print(idx) for idx in range(4)
}
funcs[0]()
did not understand what is meant by funcs[0] ? Why the index and 0 ?
This is a cool example to show how binding and scope work with lambda functions. As Daniel said, funcs is a dictionary of functions with four elements in it (with keys 0,1,2 and 3). What is interesting is that you call the function at key 0, you expect the index (idx) that was used to create that key to then print out and you'll get 0. BUT I believe if you run this code, you actually print 3! WHAT!?!? So what is happening is that the lambda function is actually not binding the value of 0 when it stores the reference to the function. That means, when the loop finishes, the variable idx has 3 associated with it and therefore when you call the lambda function in position 0, it looks up the reference to the variable idx and finds the value 3 and then prints that out. Fun :)
That was referring more to your question title than to the test... The 0 is to access the function that has key 0 in the dictionary.

Categories