我在Python hitchhikers 指南中看到了这个例子:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
Run Code Online (Sandbox Code Playgroud)
上面的示例是对后期绑定引起的一些问题的解决方案,其中在调用内部函数时查找闭包中使用的变量。
i=i 是什么意思以及为什么会产生如此大的差异?
它实际上不仅仅适用于 lambda;它还适用于 lambda。任何采用默认参数的函数都将使用相同的语法。例如
def my_range(start, end, increment=1):
ans = []
while start < end:
ans.append(start)
start += increment
return ans
Run Code Online (Sandbox Code Playgroud)
(这实际上并不是范围的工作原理,我只是认为这将是一个易于理解的简单示例)。在这种情况下,你可以打电话my_range(5,10),你会得到[5,6,7,8,9]。但你也可以打电话my_range(5,10,increment=2),这会给你[5, 7, 9]。
使用默认参数可以得到一些令人惊讶的结果。正如这篇优秀的文章所描述的,参数是在函数定义处绑定的,而不是您所期望的在函数调用处绑定的。这会导致一些奇怪的行为,但它实际上对我们有帮助。考虑您的链接中提供的错误代码:
def create_multipliers():
return [lambda x : i * x for i in range(5)]
for multiplier in create_multipliers():
print multiplier(2)
Run Code Online (Sandbox Code Playgroud)
当你打电话时multiplier(2),它实际上在做什么?它接受您的输入参数 2,并返回i * 2。但什么是i?该函数在其自己的作用域中没有调用任何变量i,因此它检查周围的作用域。在周围范围内, 的值i就是您留下的任何值 - 在本例中为 4。因此每个函数都会为您提供 8。
另一方面,如果您提供默认参数,则该函数将i在其自己的范围内调用一个变量。有什么价值i?好吧,您没有提供一个,因此它使用其默认值,该值是在定义函数时绑定的。当定义函数时,i列表中的每个函数都有不同的值!
有点令人困惑的是,他们对参数变量使用了与迭代变量相同的名称。我怀疑你可以获得相同的结果,并且具有更高的可读性
def create_multipliers():
return [(lambda x, y=i: y*x) for i in range(5)]
Run Code Online (Sandbox Code Playgroud)