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
?
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With