Я предполагаю, что лямбда, которую Вы создаете в понимании списка, связывается с переменной i, который в конечном счете заканчивается в 5. Таким образом, когда Вы оцениваете лямбды после факта, они все связываются с 5 и заканчивают тем, что вычислили 25. То же самое происходит с цифрой в Вашем втором примере. То, когда Вы оцениваете лямбду в цикле, это - цифра, не изменилось так, Вы получаете правильное значение. После цикла цифра равняется 5...
я не совсем уверен, для чего Вы идете, таким образом, я не уверен, как предложить решение. Как насчет этого?
def square(x): return lambda : x*x
listOfLambdas = [square(i) for i in [1,2,3,4,5]]
for f in listOfLambdas: print f()
Это дает мне ожидаемый вывод:
1
4
9
16
25
Другой способ думать это - то, что лямбда "получает" свою лексическую среду в точке, где это создается. Так, при предоставлении его цифра , это на самом деле не разрешает что значение до его вызванного. Это и сбивает с толку и мощно.
Вы имеете:
listOfLambdas = [lambda: i*i for i in range(6)]
for f in listOfLambdas:
print f()
Вывод:
25
25
25
25
25
25
Вам нужно приправление карри! Кроме того, чтобы быть восхитительным, используйте это значение по умолчанию "взлом".
listOfLambdas = [lambda i=i: i*i for i in range(6)]
for f in listOfLambdas:
print f()
Вывод:
0
1
4
9
16
25
Примечание i=i
. Это - то, где волшебство происходит.
listOfLambdas = [lambda i=i: square(i) for i in listOfNumbers]
Или
listOfLambdas = map(lambda i: lambda: square(i), listOfNumbers)
Я иногда нахожу, что определение фактических классов для функциональных объектов помогает понять то, что продолжается:
>>> class square(object):
... def __init__(self, val):
... self.val = val
... def __call__(self):
... return self.val * self.val
...
>>> l = [1,2,3,4,5]
>>> funcs = [square(i) for i in l]
>>> for f in funcs:
... print f()
...
1
4
9
16
25
>>>
Предоставленный, это является более подробным, чем использование лямбд или закрытий, но я нахожу это легче понять, когда я пытаюсь сделать неочевидные вещи с функциями.
Когда функциональные операторы выполняются, они связываются со своим (лексически) включающим объемом.
В Вашем отрывке, лямбды связываются с глобальной областью видимости, потому что for
комплекты не выполняются как независимо ограниченная по объему единица в Python. В конце for
цикл, эти num
связывается в объеме включения. Демонстрация:
for num in range(1, 6):
pass
assert num == 5 # num is now bound in the enclosing scope
Поэтому при привязке идентификаторов в for
цикл, Вы на самом деле управляете объемом включения.
for num in range(1, 6):
spam = 12
assert num == 5 # num is now bound in the enclosing scope
assert spam == 12 # spam is also bound in the enclosing scope
То же соглашение для пониманий списка:
[num for num in range(1, 6)]
assert num == 5
Сногсшибательный, я знаю. Anywho, с нашим новооткрытым знанием, мы можем решить, что лямбды, которые Вы создаете, обращаются к (синглу) num
идентификатор, связанный в объеме включения. Это должно заставить это иметь больше смысла:
functions = []
for number in range(1, 6):
def fun():
return number
functions.append(fun)
assert all(fun() == 5 for fun in functions)
assert all(fun() is number for fun in functions)
И вот самая прохладная часть, которая демонстрирует это еще больше:
# Same as above -- commented out for emphasis.
#functions = []
#for number in range(1, 6):
# def fun():
# return number
# functions.append(fun)
#assert all(fun() == 5 for fun in functions)
#assert all(fun() is number for fun in functions)
number = 6 # Rebind 6 in the scope and see how it affects the results.
assert all(fun() == 6 for fun in functions)
, Таким образом, решение этого, конечно, состоит в том, чтобы сделать новый объем включения для каждого number
, Вы хотите связать. В Python можно создать новые объемы включения с модулями, классами и функциями. Распространено использовать функцию только для создания нового объема включения для другой функции.
В Python, закрытие является функцией что возвраты другая функция . Отчасти как функциональный конструктор. Выезд get_fun
в следующем примере:
def get_fun(value):
""":return: A function that returns :param:`value`."""
def fun(): # Bound to get_fun's scope
return value
return fun
functions = []
for number in range(1, 6):
functions.append(get_fun(number))
assert [fun() for fun in functions] == range(1, 6)
С тех пор get_fun
функция, это добирается, чтобы иметь ее собственный внутренний объем. Каждый раз, когда Вы звоните get_fun
со значением, немного таблицы составлено для отслеживания привязку в нем; т.е. это говорит, "В этом объеме, value
идентификатор указывает на вещь, которая была передана". Тот объем уходит в конце функционального выполнения, если нет причина его для брожения вокруг.
, Если Вы возвращаете функцию из объема, это - серьезное основание для частей "таблицы объема" для брожения вокруг - которые функционируют, Вы возвращаетесь, мог сослаться на вещи от той таблицы объема, когда Вы называете его позже. По этой причине, когда fun
создается в [1 118], Python говорит fun
приблизительно [1 120] таблица объема, которая fun
сохраняет удобной для того, когда это необходимо.
можно читать больше о деталях и технической терминологии (который я смягчил немного) в документы Python о модели выполнения . Можно также посмотреть на части объема включения, к которому относится функция с [1 122]. В вышеупомянутом мы видим ссылку на эти value
, который, оказывается, интервал:
# Same as before, commented out for emphasis.
#functions = []
#for number in range(1, 6):
# functions.append(get_fun(number))
#assert [fun() for fun in functions] == range(1, 6)
print functions[0].__closure__
# Produces: (<cell at 0x8dc30: int object at 0x1004188>,)