13

I need to store functions in a dictionary, each function depending on its key, lets say, for a key 1 the lambda function associated is lambda s: s * A[1]. I tried with dict comprehension but it seems that the inline functions ends defined with the last value of the loop.

d = {k, lambda s: s * A[k] for k in range(n)}  # e.g. n = 4

After that all lambda functions created are declared with A[3] instead of A[0], A[1], A[2] and A[3]. What's wrong with this code?

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Alejandro Sazo
  • 796
  • 15
  • 31
  • at least the print of the object generated is indeed four functions with four keys, 0, 1, 2, 3. The doc of dict comprehension says that this sould be correct... I think https://www.python.org/dev/peps/pep-0274/ – Alejandro Sazo Jul 15 '15 at 04:47
  • Just curious what you're using this for and what would A and s be? – Scott Jul 15 '15 at 04:52
  • 7
    It is a common gotcha. http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures – Konstantin Jul 15 '15 at 04:54
  • 1
    @Scott I want to store some funcions involving basic operations (A is just an array, eg numpy array), then using some data structure like a tree i want to get the right indexes to evaluate the desired functions that i found in the leaves, but is just and idea :) – Alejandro Sazo Jul 15 '15 at 04:57

2 Answers2

13

A way to fix it is to change the code to:

d = {k: lambda s, k=k: s * A[k] for k in range(n)}

Without the binding, Python looks up the "current" k when each lambda is called, which is always n-1 in the original code.

YS-L
  • 14,358
  • 3
  • 47
  • 58
4

The issue occurs, because the contents of the lambda function are not executed until the lambda function is executed.

Hence, whenever you are trying to call lambda function, it works on the latest value of k (if you do del k and try to call the lambda function you should get an error).

The answer by @YS-L should be good for you.

Another way to do it, would be to make the value of the dictionaries a bound method ,binding the value of k. Example -

>>> d = {k:(lambda k,s: s * A[k]).__get__(k) for k in range(n)}
>>> d
{0: <bound method int.<lambda> of 0>, 1: <bound method int.<lambda> of 1>, 2: <bound method int.<lambda> of 2>, 3: <bound method int.<lambda> of 3>}
>>> A
[1, 2, 3, 4]
>>> d[0](1)
1
>>> d[1](1)
2
>>> d[2](1)
3
>>> d[3](1)
4
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176