Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python lambda as constant functor

Tags:

python

lambda

I have code with labdas, I have checked each time the function object is created it is different (not reference to same object), but it doesn't work as I would expect it. Is there any way how to or I should use a functor to do it even if I have constant data which I insert into lambda`s body?

pairs = [('abc', 'xyz'), ('123', '987'), ('abc', '987')]

pairLambs = []

for p in pairs:
    pairLambs.append(lambda: print(p))

pairLambs[0]()
pairLambs[1]()
pairLambs[2]()

outputs:

('abc', '987')
('abc', '987')
('abc', '987')

but I need:

('abc', 'xyz')
('123', '987')
('abc', '987')
like image 287
karna7 Avatar asked Jul 11 '14 09:07

karna7


3 Answers

This is a well-known gotcha - since you don't bind the current value of p when defining the lambda, when called it uses the current value of p. The solution is to use a named arg with default value to bind the "current" (definition time) value of p:

pairs = [('abc', 'xyz'), ('123', '987'), ('abc', '987')]

pairLambs = []

for p in pairs:
    pairLambs.append(lambda p=p: print(p))

pairLambs[0]()
pairLambs[1]()
pairLambs[2]()
like image 79
bruno desthuilliers Avatar answered Sep 20 '22 12:09

bruno desthuilliers


If you want to 'specialize' function, you should take a look at functools:

import functools

pairs = [('abc', 'xyz'), ('123', '987'), ('abc', '987')]
pairLambs = []
for p in pairs:
    pairLambs.append(functools.partial(print, p))

This gives result you expect.

like image 20
m.wasowski Avatar answered Sep 22 '22 12:09

m.wasowski


This is how closures in python work. To achive what you want you can do this:

 for p in pairs:
     def closure(_p):
         return lambda: print(_p)
     pairLambs.append(closure(p))
like image 20
ambi Avatar answered Sep 21 '22 12:09

ambi