Python PyQt-从字典创建按钮

Python PyQt-从字典创建按钮,python,pyqt,Python,Pyqt,我有一本字典。 我需要创建带有键名的按钮,并根据值单击插槽: dic = {'a':'111', 'b':'222', 'c':'333'} for key in dic: btn = QPushButton(key, self) btn.clicked.connect(lambda: doit(dic[key])) vbox.addWidget(btn) 我所有的按钮都有正确的名字。最后创建的按钮的行为正确。 但是所有其他按钮的点击插槽也连接到最后创建的按钮do('

我有一本字典。
我需要创建带有键名的按钮,并根据值单击
插槽:

dic = {'a':'111', 'b':'222', 'c':'333'}

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(lambda: doit(dic[key]))
    vbox.addWidget(btn)
我所有的按钮都有正确的名字。最后创建的按钮的行为正确。
但是所有其他按钮的
点击
插槽也连接到最后创建的按钮
do('333')


如何使所有按钮的行为都有所不同?

我认为问题在于,当您调用lambda:doit(dic[key])时,它确实会这样做,并查找dic[key],此时key被设置为上一个迭代通过的项

试试这个:

dic = {'a':'111', 'b':'222', 'c':'333'}

def create_connect(x):
    return lambda: doit(x)

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(create_connect(dic[key]))
    vbox.addWidget(btn)

我认为问题在于,当您调用lambda:doit(dic[key])时,它实际上就是这样做的,并查找dic[key],此时key被设置为迭代通过的最后一项是什么

试试这个:

dic = {'a':'111', 'b':'222', 'c':'333'}

def create_connect(x):
    return lambda: doit(x)

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(create_connect(dic[key]))
    vbox.addWidget(btn)

匿名函数
lambda:doit(dic[key])
在调用该函数之前不会计算
key
。此时,循环的
已完成,循环的
变量
key
引用了
dic
中的最后一个键

调用匿名函数时(当您按下按钮时),
key
将在全局命名空间中查找,并返回当前值
key

为了避免这个陷阱,可以在
lambda
表达式中使用默认参数:

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(lambda key=key: doit(dic[key]))
    vbox.addWidget(btn)
默认参数在定义时计算,而不是在调用lambda时计算。通过执行此操作,
key
将在匿名函数的本地名称空间中查找,而不是在全局名称空间中查找,并且由于key的本地名称空间值被设置为默认值,这对于for循环的每次传递都是不同的,因此您可以获得
key
的正确值


这也在本文中进行了解释。

匿名函数
lambda:doit(dic[key])
在调用该函数之前不会计算
key
。此时,循环的
已完成,循环的
变量
key
引用了
dic
中的最后一个键

调用匿名函数时(当您按下按钮时),
key
将在全局命名空间中查找,并返回当前值
key

为了避免这个陷阱,可以在
lambda
表达式中使用默认参数:

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(lambda key=key: doit(dic[key]))
    vbox.addWidget(btn)
默认参数在定义时计算,而不是在调用lambda时计算。通过执行此操作,
key
将在匿名函数的本地名称空间中查找,而不是在全局名称空间中查找,并且由于key的本地名称空间值被设置为默认值,这对于for循环的每次传递都是不同的,因此您可以获得
key
的正确值


这也在本文中进行了解释。

您的迭代需要字典dic的键和值。 您可以使用dict.iteritems()方法。
如果lambda变得混乱,那么最好使用partial

试试这个:

from PyQt4.QtGui import QApplication, QWidget, QVBoxLayout, QPushButton
from functools import partial

class MainWidget(QWidget):
    def __init__(self):
         super(MainWidget, self).__init__()

         dic = {'a':'111', 'b':'222', 'c':'333'}
         vbox = QVBoxLayout(self)

         for key,val in dic.iteritems():
             btn = QPushButton(key, self)
             btn.clicked.connect(partial(self.doit, val))
             vbox.addWidget(btn)


    def doit(self, text):
        print "%s" % text

if __name__ == "__main__":
    app = QApplication([])
    w = MainWidget()
    w.show()
    app.exec_()

迭代需要字典dic的键和值。 您可以使用dict.iteritems()方法。
如果lambda变得混乱,那么最好使用partial

试试这个:

from PyQt4.QtGui import QApplication, QWidget, QVBoxLayout, QPushButton
from functools import partial

class MainWidget(QWidget):
    def __init__(self):
         super(MainWidget, self).__init__()

         dic = {'a':'111', 'b':'222', 'c':'333'}
         vbox = QVBoxLayout(self)

         for key,val in dic.iteritems():
             btn = QPushButton(key, self)
             btn.clicked.connect(partial(self.doit, val))
             vbox.addWidget(btn)


    def doit(self, text):
        print "%s" % text

if __name__ == "__main__":
    app = QApplication([])
    w = MainWidget()
    w.show()
    app.exec_()

但是怎么做呢?这与
有何联系?这个把戏有名字吗?如果没有for,就不需要这个哑函数。我认为
lambda:
解决了所有这些问题。但是情况变得更糟了,但是怎么会呢?这与
有何联系?这个把戏有名字吗?如果没有for,就不需要这个哑函数。我认为
lambda:
解决了所有这些问题。但情况变得更糟了。谢谢你们的回答和链接,我开始明白了。Bwmat的方法正在工作,但是
lambda key=key:
lambda key=key:self.label.setText(key)
返回
TypeError:QLabel.setText(str):参数1有意外的类型“bool”
。如果没有
key=key
,它的工作原理与问题中的一样。我不明白
bool
从哪里来。@Qiao:using
lambda key=key:
在没有参数传递给lambda函数的情况下有效。这允许
采用默认值。如果参数被传递给lambda函数,那么
key
将被指定该值。看起来有一个布尔值被传递到lambda函数,并被分配到
。感谢您的回答和链接,我开始获取它。Bwmat的方法正在工作,但是
lambda key=key:
lambda key=key:self.label.setText(key)
返回
TypeError:QLabel.setText(str):参数1有意外的类型“bool”
。如果没有
key=key
,它的工作原理与问题中的一样。我不明白
bool
从哪里来。@Qiao:using
lambda key=key:
在没有参数传递给lambda函数的情况下有效。这允许
采用默认值。如果参数被传递给lambda函数,那么
key
将被指定该值。看起来有一个布尔值被传递到lambda函数,并被分配到