Ответ 1
Используйте эту строку вместо:
lambdas_list.append(lambda obj=obj: obj.some_var)
Возможный дубликат:
Что делает захват функции лямбда-функции в Python?
лямбда-функция не закрывает параметр в Python?
Я пытаюсь создать lambdas внутри цикла, который выполняет итерацию над списком объектов:
lambdas_list = []
for obj in obj_list:
lambdas_list.append(lambda : obj.some_var)
Теперь, если я перебираю список lambdas и вызываю их следующим образом:
for f in lambdas_list:
print f()
Я получаю то же значение. Это значение последнего obj
в obj_list
, так как это была последняя переменная в блоке итератора списка. Любые идеи fn хорошего (питонова) переписывают код, чтобы заставить его работать?
Используйте эту строку вместо:
lambdas_list.append(lambda obj=obj: obj.some_var)
Вам нужно либо захватить переменную, используя назначения по умолчанию
lambdas_list = [ lambda i=o: i.some_var for o in obj_list ]
или используйте закрытие для захвата переменной
lambdas_list = [ (lambda a: lambda: a.some_var)(o) for o in obj_list ]
В обоих случаях ключ должен удостовериться, что каждому значению в списке obj_list присваивается уникальная область.
Ваше решение не работает, потому что лексическая переменная obj
ссылается на родительскую область (for
).
Работа по умолчанию работала, потому что мы ссылаемся на i
из области lambda
. Мы используем назначение по умолчанию, чтобы сделать "передачу" переменной неявной, сделав ее частью определения lambda
и, следовательно, ее областью.
Решение замыкания работает, потому что переменная "передача" является явной, во внешнюю lambda
, которая немедленно выполняется, тем самым создавая привязку во время понимания списка и возвращая внутренний lambda
, который ссылается на эту привязку. Поэтому, когда на самом деле выполняется внутренний lambda
, он будет ссылаться на привязку, созданную во внешней области lambda
.
Вы можете сделать что-то вроде этого:
def build_lambda(obj):
return lambda : obj.some_var
lambdas_list = []
for obj in obj_list:
lambdas_list.append(build_lambda(obj))