Python 闭包,默认参数与 functools.partial 的解决方案不一致?
我正在用Python 3.2和PyQt做一个小游戏。我需要在菜单中插入一些操作,这些操作几乎是一样的,只是参数不同。我想到了用lambda表达式来实现,但结果发现所有的操作都用了同一个参数。
这其实是一个闭包的问题,我根据这个帖子解决了它。不过,有一个提议的解决方案(使用默认参数)本该和另一个方案等效,但它却不管用。当我用print函数做了一个小测试时,发现这两个方案的结果是一样的。
我想搞明白为什么在这种情况下它们的表现不同。是connect方法影响了它吗?这可能和Python的作用域有关。这是我正在做的代码片段(我省略了给操作命名和设置文本的部分):
cardsOptions = [15, 30, 45, 50, 55, 60, 10]
self.startActions = []
lambdas = []
for co in cardsOptions:
action = QtGui.QAction(MainWindow)
self.menuNewGame.addAction(action)
# This works
# action.triggered.connect(partial(self.StartGame, 8, co))
lamb = (lambda a = co: self.StartGame(8, a))
lambdas.append(lamb)
# This doesn't work, when StartGame is called it gets arguments 8, false
action.triggered.connect(lamb)
self.startActions.append(action)
# This proves that closure was done ok, and it saved all co values
[m() for m in lambdas]
让我最惊讶的是,它把false作为第二个参数传递,就好像它在评估a = co一样。那么,使用默认参数的闭包和使用部分应用有什么不同,为什么会这样工作呢?
1 个回答
4
但是如果你写:
[m(False) for m in lambdas]
这会把参数8和False传给StartGame。
Qt可能在调用你的lambda函数时传入了False
这个参数,所以lambda函数里的默认参数根本没用上。
不过你的想法很好。试试下面这个:
lamb = (lambda a, real_co = co : self.StartGame(8, real_co))
现在False
就被忽略了,真正的real_co值会被使用。