Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lambda i=i: foo(i) in for loop not working

First read this. It is about lambda x=x: foo(x) catching x even in for loop.

This is a window with label and two buttons generated in for loop. When button is clicked, it name appears in label.

If we use usual lambda: label.setText("button -- " + str(i)), then the result is last i in the loop, no matter what button is pressed:
lambda:foo(i)
And this is right.

When we change to lambda i=i: label.setText("button -- " + str(i)) (snipet) and expect that now it will be everything ok, the result is:
lambda i=i:foo(i)]
False!

Where this False comes from?

import sys
from PyQt4.QtGui import *

class MainWindow(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        vbox = QVBoxLayout(self)

        # label for action
        label = QLabel('')
        vbox.addWidget(label)

        # adding buttons
        for i in range (1, 3):
            btn = QPushButton(str(i))
            btn.clicked.connect( lambda i=i: label.setText("button " + str(i)) )
            vbox.addWidget(btn)

app = QApplication(sys.argv)
myapp = MainWindow()
myapp.show()
sys.exit(app.exec_())

Why this solution is not working as it should be? What this false means?

I know that you can make foo_factory, as in first link, but the question is what is wrong with lambda i=i: foo(i)

like image 757
Qiao Avatar asked May 28 '11 01:05

Qiao


2 Answers

I don't have PyQt4 installed to test at this very instant, but it seems clear to me that when your lambda callback is called, it's being given an argument. i is then equal to whatever the argument is, instead of the default value. Try this and tell me if it works (or if it at least changes the output):

btn.clicked.connect( lambda throw_away=0, i=i: label.setText("button " + str(i)) )
like image 130
senderle Avatar answered Sep 29 '22 10:09

senderle


Signal "clicked" passes a boolean argument to your connected lambda slot.
Documentation

What you are trying to accomplish is better done by this:

btn.clicked.connect( lambda clicked, i=i : label.setText("button " + str(i)) )
like image 41
pedrotech Avatar answered Sep 29 '22 11:09

pedrotech