luk*_*kad 9 python signals-slots pyqt4
我试图用PyQt4构建一个计算器并连接来自按钮的'clicked()'信号并不像预期的那样.我在for循环中为数字创建我的按钮,然后尝试连接它们.
def __init__(self):
for i in range(0,10):
self._numberButtons += [QPushButton(str(i), self)]
self.connect(self._numberButtons[i], SIGNAL('clicked()'), lambda : self._number(i))
def _number(self, x):
print(x)
Run Code Online (Sandbox Code Playgroud)
当我点击按钮时,所有按钮都打印出'9'.为什么会这样,我该如何解决这个问题呢?
lun*_*orn 14
这就是Python中定义的范围,名称查找和闭包的方式.
Python仅通过赋值和函数参数列表在命名空间中引入新的绑定. i因此,实际上并没有在名称空间中定义lambda,而是在名称空间中定义__init__().因此i,lambda中的名称查找最终会__init__()在i最终绑定到的命名空间中9.这称为"封闭".
通过传递i具有默认值的关键字参数,您可以解决这些通常不是非常直观(但定义良好)的语义.如上所述,参数列表中的名称在本地名称空间中引入了新的绑定,因此i在其中lambda变得独立i于.__init__():
self._numberButtons[i].clicked.connect(lambda i=i: self._number(i))
Run Code Online (Sandbox Code Playgroud)
更具可读性,更少魔力的替代方案是functools.partial:
self._numberButtons[i].clicked.connect(partial(self._number, i))
Run Code Online (Sandbox Code Playgroud)
我在这里使用新式信号和插槽语法只是为了方便,旧式语法的工作原理相同.