creating a dictionary with anonymous functions in Python

Question:

I have a vector with some parameters and I would like to create a dictionary of anonymous (lambda) functions in Python3.

The goal of this is to create a callable function that gives values equal to the sum of these functions with the same argument.

I am struggling even to create a dictionary with the original lambda function objects and get them to behave consistently. I use the following code:

import numpy as np

a = np.linspace(0,2.0,10)
func = {}
for i,val in enumerate(a):
  print(i)
  func['f{}'.format(i)] = lambda x: x**val

print(func['f0'](0.5))
print(func['f1'](0.5))
print(func['f2'](0.5))
print(func['f3'](0.5))

The output of the final print statements gives the same value, whereas I would like it to give the values corresponding to x**val with the value of val coming from the originally constructed array a.

I guess what’s happening is that the lambda functions always reference the “current” value of val, which, after the loop is executed is always the last value in the array? This makes sense because the output is:

0
1
2
3
4
5
6
7
8
9
0.25
0.25
0.25
0.25

The output makes sense because it is the result of 0.5**2.0 and the exponent is the last value that val takes on in the loop.

I don’t really understand this because I would have thought val would go out of scope after the loop is run, but I’m assuming this is part of the “magic” of lambda functions in that they will keep variables that they need to compute the function in scope for longer.

I guess what I need to do is to insert the “literal” value of val at that point into the lambda function, but I’ve never done that and don’t know how.

I would like to know how to properly insert the literal value of val into the lambda functions constructed at each iteration of the loop. I would also like to know if there is a better way to accomplish what I need to.

EDIT: it has been suggested that this question is a duplicate. I think it is a duplicate of the list comprehension post because the best answer is virtually identical and lambda functions are used.

I think it is not a duplicate of the lexical closures post, although I think it is important that this post was mentioned. That post gives a deeper understanding of the underlying causes for this behavior but the original question specifically states “mindful avoidance of lambda functions,” which makes it a bit different. I’m not sure what the purpose of that mindful avoidance is, but the post did teach related lessons on scoping.

Asked By: villaa

||

Answers:

The problem with this approach is that val used inside your lambda function is the live variable, outside. When each lambda is called, the value used for val in the formula is the current value of val, therefore all your results are the same.

The solution is to “freeze” the value for val when creating each lambda function – the way that is easier to understand what is going on is to have an outer lambda function, that will take val as an input, and return your desided (inner) lambda – but with val frozen in a different scope. Note that the outer function is called and imedially discarded – its return value is the original function you had:


for i,val in enumerate(a):
  print(i)
  func[f'f{i}'] = (lambda val: (lambda x: x**val))(val)

shorter version

Now, due to the way Python stores default arguments to functions, it is possible to store the “current val value” as a default argument in the lambda, and avoid the need for an outer function. But that spoils the lambda signature, and the “why” that value is there is harder to understand –


for i,val in enumerate(a):
  print(i)
  func[f'f{i}'] = lambda x, val=val: x**val
Answered By: jsbueno