循环连接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)
当我单击按钮时,它们全部都打印出“ 9”。为什么会这样,我该如何解决呢?
问题答案:
这就是在Python中定义作用域,名称查找和闭包的方式。
Python仅通过分配和函数的参数列表在名称空间中引入新的绑定。
i
因此,实际上不是在的名称空间中定义lambda
,而是在的名称空间中定义__init__()
。对于名称查找i
在lambda中的命名空间从而结束了__init__()
,在i
最终必然9
。这称为“关闭”。
您可以通过传递i
带有默认值的关键字参数来解决这些公认的非直觉(但定义明确)的语义。如前所述,参数列表中的名称在本地名称空间中引入了新的绑定,因此theni
内部lambda
变得独立于i
in
.__init__()
:
self._numberButtons[i].clicked.connect(lambda i=i: self._number(i))
更具可读性,更少魔术性的替代方法是functools.partial
:
self._numberButtons[i].clicked.connect(partial(self._number, i))
为了方便起见,我在这里使用新型信号和插槽语法,而老式语法的工作原理相同。