Закрытие Python, аргумент по умолчанию не является таким же решением, как использование functools.partial - PullRequest
3 голосов
/ 07 ноября 2011

Я делаю небольшую игру на Python 3.2 с использованием PyQt.Мне нужно было вставить в меню действия, которые делали почти то же самое, но с другими параметрами.Я понял, что сделаю это с использованием лямбд, но оказалось, что все действия имеют одинаковый параметр.

Это оказалось проблемой закрытия, которую я решил согласно этому посту по другому такому вопросу.Но одно из предложенных решений (с аргументом по умолчанию), которое должно быть эквивалентно другому, не работает.Когда я провел небольшой тест с функцией печати, оба решения были равны.

Я бы хотел понять, почему в этом случае все работает иначе.Это как-то влияет на метод 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 голосов
/ 07 ноября 2011

Но если вы напишите:

[m(False) for m in lambdas]

Он вызовет StartGame с аргументами 8, также False.

Qt, вероятно, вызывает ваши лямбды с аргументом False, поэтомуАргумент по умолчанию лямбда просто не используется.

Но ваша идея хороша.Попробуйте выполнить следующее:

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

Теперь False просто игнорируется и используется значение real_co.

...