将lambda函数存储到字典中时,我遇到了一些奇怪的行为:如果尝试将某个默认值传递给循环中的函数,则只使用最后一个默认值。
这里有一些最小的例子:
$(document).ready(function() {
$( ".datepicker-date" ).datepicker({
dateFormat: "dd-mm-yy",
changeMonth: true,
changeYear: true
});
});
输出如下:
#!/usr/bin/env python
# coding: utf-8
def myfct(one_value, another_value):
"do something with two int values"
return one_value + another_value
fct_dict = {'add_{}'.format(number): (lambda x: myfct(x, number))
for number in range(10)}
print('add_3(1): {}, id={}'.format(fct_dict['add_3'](1), id(fct_dict['add_3'])))
print('add_5(1): {}, id={}'.format(fct_dict['add_5'](1), id(fct_dict['add_5'])))
print('add_9(1): {}, id={}'.format(fct_dict['add_9'](1), id(fct_dict['add_9'])))
你得到不同的函数(id不相同),但每个函数使用相同的第二个参数。
有人可以解释一下发生了什么吗?
同样适用于python2,python3,pypy ......
答案 0 :(得分:9)
修复:
def make_closure(number):
return lambda x: myfct(x, number)
用作
{'add_{}'.format(number): make_closure(number) for number in range(10)}
这种行为的原因是,变量number
(想想:这里命名的内存位置)在循环的所有迭代期间是相同的(尽管它的实际值在每次迭代中都会改变)。这里的“循环”是指字典理解,它在内部基于循环。在循环中创建的所有lambda
实例将关闭相同的“位置”,该位置保留最后分配给它的值(在循环的最后一次迭代中)。
以下代码不下面实际发生的事情。它仅用于阐明概念:
# Think of a closure variable (like number) as being an instance
# of the following class
class Cell:
def __init__(self, init=None):
self.value = None
# Pretend, the compiler "desugars" the dictionary comprehension into
# something like this:
hidden_result_dict = {}
hidden_cell_number = Cell()
for number in range(10):
hidden_cell_number.value = number
hidden_result_dictionary['add_{}'.format(number)] = create_lambda_closure(hidden_cell_number)
lambda
操作创建的所有create_lambda_closure
个闭包共享同一个Cell
实例,并在运行时获取value
属性(即关闭时实际上被称为)。到那时,value
将引用分配给它的最后一个值。
然后回答hidden_result_dict
的值作为词典理解的结果。 (同样:这只是在“概念”级别上阅读;它与Python VM执行的实际代码无关。)
答案 1 :(得分:3)
number
是一个变量,它对于dict理解的每次迭代都有不同的值。但是当您执行lambda x: myfct(x, number)
时,它不会使用number
的值。它只是创建一个lambda方法,它将在调用/使用时使用number的值。因此,当您使用add_{}
方法时,number
的值9
会在myfct(x, number)
的每次调用中使用。