Python Lambda в цикле

Учитывая следующий фрагмент кода:

# directorys == {'login': <object at ...>, 'home': <object at ...>} for d in directorys: self.command["cd " + d] = (lambda : self.root.change_directory(d)) 

Я ожидаю создать словарь из двух функций следующим образом:

 # Expected : self.command == { "cd login": lambda: self.root.change_directory("login"), "cd home": lambda: self.root.change_directory("home") } 

но похоже, что две генерируемые лямбда-функции точно такие же:

 # Result : self.command == { "cd login": lambda: self.root.change_directory("login"), "cd home": lambda: self.root.change_directory("login") # <- Why login ? } 

Я действительно не понимаю, почему. Есть ли у вас какие-либо предложения ?

  • Выпуск синтаксического анализа страницы xhtml с использованием Python
  • Как изменить цвет текстового курсора в Tkinter?
  • Почему (0-6) -6 = False?
  • TDD - проблемы начинающих и камни преткновения
  • Разделить фрагмент тела html в lxml
  • Создать .exe с Pyinstaller ERROR: сборка amd64_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_none не найден
  • Выбор и развертывание кометного сервера
  • Запрос многих из многих полей в шаблоне django
  • 2 Solutions collect form web for “Python Lambda в цикле”

    Вам нужно связать d для каждой созданной функции. Один из способов сделать это – передать его как параметр со значением по умолчанию:

     lambda d=d: self.root.change_directory(d) 

    Теперь функция d внутри функции использует параметр, даже если он имеет то же имя, а значение по умолчанию для этого оценивается при создании функции. Чтобы это можно было увидеть:

     lambda bound_d=d: self.root.change_directory(bound_d) 

    Помните, как работают значения по умолчанию, например, для изменяемых объектов, таких как списки и dicts, потому что вы привязываете объект.

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

     (lambda d=d: lambda: self.root.change_directory(d))() # or (lambda d: lambda: self.root.change_directory(d))(d) 

    Еще лучше, редизайн того, как вы обрабатываете «команды», поможет здесь и должен помочь в другом месте.

    Это связано с точкой, в которой d связан. Лямбда-функции все указывают на переменную d а не на текущее значение , поэтому, когда вы обновляете d в следующей итерации, это обновление видно по всем вашим функциям.

    Для более простого примера:

     funcs = [] for x in [1,2,3]: funcs.append(lambda: x) for f in funcs: print f() # output: 3 3 3 

    Вы можете обойти это, добавив дополнительную функцию, например:

     def makeFunc(x): return lambda: 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 

    Однако в целом это не очень хорошая практика, так как вы изменили подпись своей функции.

    Python - лучший язык программирования в мире.