0

This issues is related to pyside(6). The following code should work, but I keep getting a single value 't' as the result when a button is clicked.

labels_list = ["y", "t", "u", "N", "T", "U"]
who_cb_list = []
for ii in range(6):
    who_cb_list.append(qtw.QRadioButton())
    who_cb_list[ii].setText(labels_list[ii])
    who_cb_list[ii].clicked.connect(lambda ii=ii: self.setWho(labels_list[ii]))

Originally I made the mistake of

    who_cb_list[ii].clicked.connect(lambda: self.setWho(labels_list[ii]))

When I clicked on the radio button of course I always connect the last value of the list ('U') on every button.

But the new way (lambda ii=ii:) still caused an error. Oddly I would always get 't'. I asked chatGPT and got this suggestion which worked.

def create_lambda_handler(label):
    return lambda: self.setWho(label)

for ii, label in enumerate(labels_list):
    who_cb_list.append(qtw.QRadioButton())
    who_cb_list[ii].setText(label)             
    who_cb_list[ii].clicked.connect(create_lambda_handler(label))

The function defined outside the loop makes a closure.... Another way to do this turned out to be using func tools:

import functools

for ii, label in enumerate(labels_list):
   who_cb_list.append(qtw.QRadioButton())
   who_cb_list[ii].setText(label)             
   who_cb_list[ii].clicked.connect(functools.partial(self.setWho, label))

From chatGPT: functools.partial is a function in the Python standard library that allows you to create partial function application. It's a way to "freeze" some portion of a function's arguments, creating a new function with those arguments pre-filled.

user2390182 provided this link which explains all this: Common Gotchas — The Hitchhiker's Guide to Python

Here is the entire exchange with chatGPT https://chat.openai.com/share/afa29ada-e97d-476c-b67d-495f657d5278

hawkiboy
  • 35
  • 6
  • I'm not sure if by "get the current value into the lambda expression" you mean executing the anonymous function with current value (ii I suppose?) as its input parameter or something else. See my answer and please elaborate. – srn Jul 08 '23 at 06:15
  • https://docs.python-guide.org/writing/gotchas/#late-binding-closures – user2390182 Jul 08 '23 at 07:42

1 Answers1

0

I'll post an answer, as this is a bit much for the comment section. I can't quite figure out what you're trying to do and what the lambda is supposed to do. I'll edit/delete later.

Is it on purpose to use both who_cb_list and self.who_cb_list ? It seems you only define the lambda (and thereby return the anonymous function itself) but never execute it (unless that's happening within connect)

For instance here I provide (i) as the input to lambda so that I get a value in return and not the function:

for i in range(6):
    a = (lambda x:x+1)(i)
    print(i,a)
0 1
1 2
2 3
...
srn
  • 614
  • 3
  • 15
  • Apologies, I have updated my question. The connect is assigning what will happen when.a radio button is pressed. When that button is pressed, it always gets the last argument in the labels_list because that is the last valid value for ii. I want to capture what the value for ii is at the time I connect the callback to the radiobutton. – hawkiboy Jul 08 '23 at 07:40
  • Understood. It happens because you return only a function (the lambda function) if you don't provide the input parameter to the lambda. You don't need *ii* inside the lambda, any placeholder var will do. You need to provide *ii* as the parameter (in my example x is the placeholder and with (i) I provide the actual value). Try if that works. – srn Jul 08 '23 at 07:44