14

I have a list of lambda functions I want to evaluate in order. I'm not sure why, but only the last function gets evaluated. Example below:

  >>> def f(x,z):
  ...     print "x=",x,", z=",z
  ... 
  >>> 
  >>> g = lambda x : f(x,13)
  >>> g(2)
  x= 2 , z= 13    # As expected
  >>> 
  >>> lst=[]
  >>> 
  >>> for i in range(0,5): 
  ...    lst.append(lambda x: f(x,i))
  ... 
  >>> print lst
  [<function <lambda> at 0x10341e2a8>, <function <lambda> at 0x10341e398>, <function <lambda> at 0x10341e410>, <function <lambda> at 0x10341e488>, <function <lambda> at 0x10341e500>]
  >>> 
  >>> for fn in lst:
  ...   fn(3)
  ... 
  x= 3 , z= 4 # z should be 0
  x= 3 , z= 4 # z should be 1
  x= 3 , z= 4 # z should be 2
  x= 3 , z= 4 # z should be 3
  x= 3 , z= 4 # as expected.

I think only the last one is getting executed, but not the others. Any ideas? Thanks!

Nawal
  • 271
  • 4
  • 10

3 Answers3

19

The lambda is just looking up the global value of 'i'.

Try the following instead:

for i in range(0,5):
  lst.append(lambda x, z=i: f(x,z))
bluepnume
  • 16,460
  • 8
  • 38
  • 48
2

try using partial, works for me:

from functools import partial

def f(x,z):
    print "x=",x,", z=",z

lst = [ partial(f,z=i) for i in range(5) ]

for fn in lst:
    fn(3)

http://docs.python.org/library/functools.html#functools.partial

Yannick Loiseau
  • 1,394
  • 8
  • 8
1

Not a Python expert, but is it possible that Python is treating i in

lst.append(lambda x: f(x,i))

as a reference? Then, after the loop, i is equal to its last assigned value (4), and when the functions are called, they follow their i reference, find 4, and execute with that value.

Disclosure: probably nonsense.

Owen
  • 1,541
  • 1
  • 14
  • 12
  • It is! (From the link given by Jon Skeet above). Thanks! – Nawal May 19 '11 at 13:28
  • You're close. The lambda function looks up `i` when it's called, and in the global scope `i` is equal to 4, given that that's the last value it was set to in the loop. – bluepnume May 19 '11 at 13:29