英文:
Function recursion not working in for loop but working outside
问题
让我们考虑以下代码:
def f(x):
return x
sol = [f]
sol.append(lambda x: sol[0](x) + x)
sol.append(lambda x: sol[1](x) + x)
print(sol[0](1), sol[1](1), sol[2](1))
# 1 2 3
以这种方式做,我得到了我想要的结果。现在,让我们使用for循环
完全相同的方式来做一遍:
def f(x):
return x
sol = [f]
for i in range(1, 3):
sol.append(lambda x: sol[i](x) + x)
print(sol[0](1), sol[1](1), sol[2](1))
# RecursionError: maximum recursion depth exceeded.
有人可以解释一下发生了什么吗?
乍一看,我认为问题类似于这个问题:lambda函数重复调用自身,直到达到递归限制。但我不明白为什么会出现这种情况。
英文:
Let's consider the following code :
def f(x):
return x
sol = [f]
sol.append(lambda x: sol[0](x) + x)
sol.append(lambda x: sol[1](x) + x)
print(sol[0](1), sol[1](1), sol[2](1))
# 1 2 3
Doing in such a way I got what I want. Now, let's do the exact same thing but with a for loop
:
def f(x):
return x
sol = [f]
for i in range(1, 3):
sol.append(lambda x: sol[i](x) + x)
print(sol[0](1), sol[1](1), sol[2](1))
# RecursionError: maximum recursion depth exceeded.
Can someone explain me what's happening ?
At first glance, I thought that the problem was similar to that one : lambda function calls itself repeatedly until it bottoms out at the recursion limit. But I do not see why that could be the case.
答案1
得分: 3
Your code creates a closure, so that when the lambdas are called, they do not use the value of i
that was in effect at the time they were created, but instead they use the current value of i
, which is 2. So it's equivalent to:
sol = [f]
sol.append(lambda x: sol[2](x) + x)
sol.append(lambda x: sol[2](x) + x)
To fix it, you need to capture the value of the loop index at the time the lambda is created. This can be done by lambda-binding the loop value (see the solutions below).
The other problem with the original code is that the loop index runs from 1 to 2, when in fact it needs to from from 0 to 1 (so that the lambdas refer to the previous functions in the list rather than to themselves).
Both problems can be fixed as follows:
sol = [f]
for i in range(0, 2):
sol.append((lambda i: lambda x: sol[i](x) + x)(i))
This produces the desired behavior. There's also a trick you can use to make it more concise:
sol = [f]
for i in range(0, 2):
sol.append(lambda x, i=i: sol[i](x) + x)
This binds i
as the default value of an optional second argument. The only difference in behavior is that the second argument can now be specified by the caller, which you may or may not want.
英文:
Your code creates a closure, so that when the lambdas are called, they do not use the value of i
that was in effect at the time they were created, but instead they use the current value of i
, which is 2. So it's equivalent to:
sol = [f]
sol.append(lambda x: sol[2](x) + x)
sol.append(lambda x: sol[2](x) + x)
To fix it, you need to capture the value of the loop index at the time the lambda is created. This can be done by lambda-binding the loop value (see the solutions below).
The other problem with the original code is that the loop index runs from 1 to 2, when in fact it needs to from from 0 to 1 (so that the lambdas refer to the previous functions in the list rather than to themselves).
Both problems can be fixed as follows:
sol = [f]
for i in range(0, 2):
sol.append((lambda i: lambda x: sol[i](x) + x)(i))
This produces the desired behavior. There's also a trick you can use to make it more concise:
sol = [f]
for i in range(0, 2):
sol.append(lambda x, i=i: sol[i](x) + x)
This binds i
as the default value of an optional second argument. The only difference in behavior is that the second argument can now be specified by the caller, which you may or may not want.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论