Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

failed to wrap function with lambda [duplicate]

Tags:

python

lambda

I want to wrap a function with specified arguments, something like functools.partial, but it doesn't work as expected:

source_codes = (0, 1, 2)

def callback(source, *args):
    print 'callback from source: ', source

funcs = []
for source in source_codes:
    funcs.append(lambda *args: callback(source, *args))

for i, func in enumerate(funcs):
    print 'source expected: ', i
    func()
    print

the output:

source expected:  0
callback from source:  2

source expected:  1
callback from source:  2

source expected:  2
callback from source:  2

But...What I want is:

source expected:  0
callback from source:  0

source expected:  1
callback from source:  1

source expected:  2
callback from source:  2

I know it works if I use functools.partial, but I want to know the real problem in my code... Does the lambda wrapper use a global variable source ?

like image 361
cherish Avatar asked Jul 22 '15 05:07

cherish


2 Answers

The issue in your code is that the lambda expression does not get evaluated untill it gets called.

And then when it gets called, it uses the latest value of source . It does not bind value of source at the time of creation of the lambda .

Example code to show this behavior -

>>> y = lambda: z
>>> z = 0
>>> y()
0
>>> z  = 1
>>> y()
1
like image 57
Anand S Kumar Avatar answered Nov 03 '22 17:11

Anand S Kumar


partial already "freezes" the function's arguments and/or keywords you passed to him so you can simply eliminate lambda expression:

source_codes = (0, 1, 2)

def callback(source, *args):
    print 'callback from source: ', source

funcs = []
for source in source_codes:
    funcs.append(partial(callback, source))
    source = 30 # don't have any effects over partial function.

for i, func in enumerate(funcs):
    print 'source expected: ', i
    func()
    print
like image 34
Ozgur Vatansever Avatar answered Nov 03 '22 17:11

Ozgur Vatansever