3

I'm doing a little game in Python 3.2 with use of PyQt. I needed to insert in menu actions which did almost the same, but with other parameters. I figured out I will do it with use of lambdas, but it turned out that all actions got the same parameter.

It turned out to be a closure problem, which i solved according to this post on other SO question. But one of the proposed solutions (with default argument) which should be equivalent to the other one, doesn't work. When I did a little test with print function both solutions were equal.

I'd like to understand it why it works different in this case. Is connect method influencing it somehow? It probably has something to do with python scopes. Here a snippet of what I'm doing (I omitted assigning names and text to actions):

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]

What surprise me the most is that it passes false as second argument, as if he evaluated a = co? So how closure with default argument is different from using partial, that it works this way?

Community
  • 1
  • 1
slawek
  • 2,709
  • 1
  • 25
  • 29

1 Answers1

4

But if you write:

[m(False) for m in lambdas]

It will call to StartGame with arguments 8,False, too.

Qt is probably calling your lambdas with argument False, so the default argument of the lambda is simply not used.

But your idea is good. Try with the following:

lamb = (lambda a, real_co = co : self.StartGame(8, real_co))

Now the False is simply ignored and the real_co value is used.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • 3
    The [QAction.triggered](http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qaction.html#triggered) signal carries with it the `checked` state of the action, which is always either True or False. For non-checkable actions, like what @slawek is creating, the checked state should be False. – Nathan Nov 06 '11 at 23:47
  • You're right, that works. I didn't think of that. To top of that now I also understand why false even got there. I thought that triggered signal has no argument, turns out I was wrong. From PyQt doc: "void triggered (bool = 0)". So mystery was solved, and here I thought all my lambdas are gonna break. Thank you. edit. Thanks @Nathan for your insight. It's always good to understand things : ] – slawek Nov 06 '11 at 23:52