What's wrong with this lambda (maybe something to do with PyQt?)

Viewed 165

I connected three buttons to a function which takes an argument and simply prints it. The buttons pass the argument in cosmetically different ways, as you can see in the MWE below, though as I far as I know there isn't any semantic difference.

from PyQt5.QtWidgets import QPushButton, QFrame, QApplication, QVBoxLayout
from functools import partial


def func(i):
    print(i)

app = QApplication([])
frame = QFrame()
layout = QVBoxLayout()
frame.setLayout(layout)

b1 = QPushButton('button 1', frame)
b1.clicked.connect(lambda: func(1))

b2 = QPushButton('button 2', frame)
b2.clicked.connect(partial(func, i=2))

b3 = QPushButton('button 3', frame)
b3.clicked.connect(lambda x=3: func(x))

layout.addWidget(b1)
layout.addWidget(b2)
layout.addWidget(b3)

frame.show()
app.exec()

So when I click the buttons 1 through 3 I expect to see

1
2
3

But instead I get

1
2
False

What's wrong with the last lambda? Could this possibly be a bug of PyQt?

PyQt version is 5.15.2.

2 Answers

I believe this is because PyQt is passing a parameter to the connect function. From the documentation for QAbstractButton, from which QPushButton inherits, the clicked slot (callbacks for signals in PyQt are called slots) will receive a checked parameter, which is a boolean. The lambda function lambda x=3: func(x) takes one parameter, x, which takes default value 3. If no parameter is passed to this slot, x will therefore take the value 3. However, PyQt passes False to this function, as specified in the clicked signal documentation, so x instead takes the value False.

You create a lambda with a default value:

lambda x=3: func(x)

But Qt passes False to it (the checked parameter), so the default argument isn't used.

Related