我有一个字符串列表,希望为每个字符串创建一个菜单项。当用户单击其中一个条目时,始终使用字符串作为参数调用相同的函数。经过一些尝试和研究,我想出了这样的办法:

import sys
from PyQt4 import QtGui, QtCore

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.menubar = self.menuBar()
        menuitems = ["Item 1","Item 2","Item 3"]
        menu = self.menubar.addMenu('&Stuff')
        for item in menuitems:
            entry = menu.addAction(item)
            self.connect(entry,QtCore.SIGNAL('triggered()'), lambda: self.doStuff(item))
            menu.addAction(entry)
        print "init done"

    def doStuff(self, item):
        print item

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

现在的问题是,每个菜单项将打印相同的输出:“项目3”,而不是相应的输出。我很感谢你对我如何才能做到这一点的任何想法。谢谢。

最佳答案

您遇到了在python中经常被称为“作用域问题”的问题(可能不是完全正确地理解;-)——绑定很晚(调用时进行词汇查找),而您希望它很早(在def时)。所以你现在的处境是:

    for item in menuitems:
        entry = menu.addAction(item)
        self.connect(entry,QtCore.SIGNAL('triggered()'), lambda: self.doStuff(item))

试试看:
    for item in menuitems:
        entry = menu.addAction(item)
        self.connect(entry,QtCore.SIGNAL('triggered()'), lambda item=item: self.doStuff(item))

这“预期”了绑定,因为默认值(这里的item值)在def时间内都会被计算一次。添加一个级别的函数嵌套(例如双lambda)也可以,但这有点过分了!-)
您也可以使用functools.partial(self.doStuff, item)(当然顶部有一个import functools)这是另一个很好的解决方案,但我认为我会选择最简单(也是最常见的)“fake default value for argument”惯用法。

08-26 19:23
查看更多