考虑以下Python 3指令
res = []
for a in range(3) :
res.append(lambda n : n + a)
旨在构建包含res
,res[0]
和res[1]
三个函数的res[2]
列表,以便res[i](n)
返回n + i
,适用于i
中的所有[0, 1, 2]
。
然而,获得
>>> res[0](0)
2
而不是
>>> res[0](0)
0
一个人也有
>>> res[1](2)
4
此行为的解释是,在示例的任何动态生成的匿名函数的正文中的表达式n + a
中,在创建函数时不评估符号a
。评估在for语句的退出处执行,解释了为什么所有函数res[0]
,res[1]
和res[2]
都返回其参数的值加2è (because
a {{1 } range(3)browses
2`是它的最后一个值。)
请注意,问题不在于我们使用匿名函数。的确,说明
and
导致相同的行为。
另请注意,我们可以使用Python的res = []
for a in range(3) :
def f(n) :
return n + a
res.append(f)
函数来实现上述目标:
eval
诀窍在于res = []
for a in range(3) :
s = "lambda n : n + %s" %(a)
res.append(eval(s))
的动态值被考虑用于创建a
的每个函数。
现在我的问题是
res
来获取预期行为的方法吗?答案 0 :(得分:3)
由于closure动态函数引用变量a
并使用它在执行时for
循环结束时的最终值。
您可以通过使其成为具有默认值的函数参数来防止这种情况,因此不需要在调用时提供它。定义每个动态函数时a
的值将成为使用的值。这就是我的意思:
res = []
for a in range(3) :
res.append(lambda n, a=a: n + a)
print(res[0](0)) # -> 0
print(res[1](2)) # -> 3
答案 1 :(得分:2)
我不能说#1 ...除了说我确信这是有意和理想的有意和可取的行为
但WRT#2
res = []
for a in range(3) :
res.append(lambda n,b=a : n + b)
res[0](0)
这将在for循环内(而不是退出后)将a
评估为默认的第二个参数...
使它开放到类似
的东西res[0](0,8)
答案 2 :(得分:0)
如果你真的不想在lambda
函数中使用两个参数,那么就有一条出路,虽然不是很漂亮:
res = []
for a in range(3):
curr_a = str(a)
exec('a' + curr_a +'=' + curr_a)
exec('func= lambda x : x + a' + curr_a)
res.append(func)
print 'res=',res[a](0)
这会在每次迭代时创建不同的变量a0
,a1
,a2
..结束a
在最后被覆盖的问题。
产生:
>>> res[0](0)
0
IMO,这不是一个好的方法,对于range(k)
k
大{{1}}会让你最终得到大量未使用的变量。
答案 3 :(得分:0)
如果您不想使用lambda
:
>>> from functools import partial
>>> for a in range(3) :
def f(a, n):
return n + a
f = partial(f, a)
res.append(f)
>>> res[0](0)
0
>>> res[1](2)
3
答案 4 :(得分:0)
这为您提供了只有一个参数的简洁函数:
res = []
for a in range(3) :
res.append((lambda a: lambda n: n+a)(a))
这样做可能会更好以便于阅读和提高效率:
def adder(amount):
return lambda n: n + amount
res = []
for a in range(3) :
res.append(adder(a))
此外,您的“评估是在for语句的退出处执行的”是错误的。在循环后尝试打印,然后再增加a
,然后再次打印。您会看到函数现在使用a
的进一步增加的值(仅适用于您的版本,当然,不是我的版本)。这是因为您的函数没有自己的a
但使用相同的全局a
,并在调用时对其进行评估。