python:(lambda)函数的dict

时间:2016-01-18 12:06:24

标签: python lambda

将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 ......

2 个答案:

答案 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)的每次调用中使用。