I am trying to create a family of functions, parametrized by a "shift" parameter. Consider the code below.
I want the for loop to create a set of functions, each of which shifts the argument by a different amount.
# Python 3 code.
N = 5
fns = []
for idx in range(N):
def f(x): # shift input by idx
return x+idx
fns.append(f)
print("---------------------------")
for i in range(N):
print(fns[i](1))
print("---------------------------")
for idx in range(N):
print(fns[idx](1))
After I run the code, I get something strange:
---------------------------
5
5
5
5
5
---------------------------
1
2
3
4
5
Why is the output from the two for loops different although they are doing conceptually the same thing?
Possible reason?: In the 2nd loop, I have reverted back to the name idx
which is the one used in the first for
loop in the creation of the list of functions.
So probably there is some "binding" magic going on here i.e. all functions basically use the value of idx
in the immediate surrounding scope during its invocation.
In the 2nd for
loop the value of idx
at the end of the first for
loop is 4, which causes the 2nd for loop to output identical results. In the 3rd for loop, idx
variable is again changing value at each iteration
which causes the functions to behave as intended in this 3rd for loop.,
Is this a correct explanation?
But this is clearly a buggy way of defining a one-parameter family of functions. What then is the Pythonic way of doing this?
Note: Some might suggest that defining the f
's in the first loop as accepting two arguments: the actual argument, and the shift parameter. In my code, for certain technical reasons I cannot do this in the code-base I am working with. Maybe currying is an option? I don't want to go there, if there is a simpler Python solution to creating a one(two,three...) parameter family of functions