# directorys == {'login': <object at ...>, 'home': <object at ...>} for d in directorys: self.command["cd " + d] = (lambda : self.root.change_directory(d))
Я ожидаю создать словарь из двух функций следующим образом :
Я действительно не понимаю почему. У вас есть какие-либо предложения?
Переведено автоматически
Ответ 1
Вам нужно привязать d для каждой созданной функции. Один из способов сделать это - передать его как параметр со значением по умолчанию:
lambda d=d: self.root.change_directory(d)
Теперь d внутри функции использует параметр, даже если он имеет то же имя, и значение по умолчанию для него вычисляется при создании функции. Чтобы помочь вам увидеть это.:
Помните, как работают значения по умолчанию, например, для изменяемых объектов, таких как списки и dicts , потому что вы привязываете объект.
Эта идиома параметров со значениями по умолчанию достаточно распространена, но может дать сбой, если вы проанализируете параметры функции и определите, что делать, основываясь на их наличии. Вы можете избежать использования параметра с помощью другого замыкания.:
(lambda d=d: lambda: self.root.change_directory(d))() # or (lambda d: lambda: self.root.change_directory(d))(d)
Ответ 2
Это связано с точкой, в которой d привязывается. Все лямбда-функции указывают на переменнуюd, а не на ее текущее значение, поэтому при обновлении d на следующей итерации это обновление будет видно во всех ваших функциях.
Для более простого примера:
funcs = [] for x in [1,2,3]: funcs.append(lambda: x)
for f in funcs: print f()
# output: 3 3 3
Вы можете обойти это, добавив дополнительную функцию, например:
defmakeFunc(x): returnlambda: x
funcs = [] for x in [1,2,3]: funcs.append(makeFunc(x))
for f in funcs: print f()
# output: 1 2 3
Вы также можете исправить область видимости внутри лямбда-выражения
lambda bound_x=x: bound_x
Однако в целом это не хорошая практика, поскольку вы изменили сигнатуру своей функции.
Ответ 3
В качестве альтернативы, вместо lambda вы можете использовать functools.partial который, на мой взгляд, имеет более чистый синтаксис.
Вместо:
for d in directorys: self.command["cd " + d] = (lambda d=d: self.root.change_directory(d))
это будет:
for d in directorys: self.command["cd " + d] = partial(self.root.change_directory, d)
Или, вот еще один простой пример:
numbers = [1, 2, 3]
lambdas = [lambda: print(number) for number in numbers] lambdas_with_binding = [lambda number=number: print(number) for number in numbers] partials = [partial(print, number) for number in numbers]
for function in lambdas: function() # 3 3 3 for function in lambdas_with_binding: function() # 1 2 3 for function in partials: function() # 1 2 3
Ответ 4
Я столкнулся с такой же проблемой. Выбранное решение мне очень помогло, но я считаю необходимым добавить точности, чтобы сделать функциональным код вопроса: определите лямбда-функцию вне цикла. Кстати, значение по умолчанию не обязательно.
foo = lambda d: lambda : self.root.change_directory(d) for d in directorys: self.command["cd " + d] = (foo(d))