I need a callback function that is almost exactly the same for a series of gui events. The function will behave slightly differently depending on which event has called it. Seems like a simple case to me, but I cannot figure out this weird behavior of lambda functions.
So I have the following simplified code below:
def callback(msg):     print msg  #creating a list of function handles with an iterator funcList=[] for m in ('do', 're', 'mi'):     funcList.append(lambda: callback(m)) for f in funcList:     f()  #create one at a time funcList=[] funcList.append(lambda: callback('do')) funcList.append(lambda: callback('re')) funcList.append(lambda: callback('mi')) for f in funcList:     f()   The output of this code is:
mi mi mi do re mi   I expected:
do re mi do re mi   Why has using an iterator messed things up?
I've tried using a deepcopy:
import copy funcList=[] for m in ('do', 're', 'mi'):     funcList.append(lambda: callback(copy.deepcopy(m))) for f in funcList:     f()   But this has the same problem.
1 Scope of a Lambda Expression. The body of a lambda expression has the same scope as a nested block. The same rules for name conflicts and shadowing apply. It is illegal to declare a parameter or a local variable in the lambda that has the same name as a local variable.
Lambda Expressions were added in Java 8. A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.
A lambda function can have any number of parameters, but the function body can only contain one expression. Moreover, a lambda is written in a single line of code and can also be invoked immediately.
To configure a REST API to pass query string parameters to a backend Lambda function, use a Lambda custom integration. To pass query string parameters to an HTTP endpoint, use an HTTP custom integration. Important:Make sure that the input data is supplied as the integration request payload.
When a lambda is created, it doesn't make a copy of the variables in the enclosing scope that it uses. It maintains a reference to the environment so that it can look up the value of the variable later. There is just one m. It gets assigned to every time through the loop. After the loop, the variable m has value 'mi'. So when you actually run the function you created later, it will look up the value of m in the environment that created it, which will by then have value 'mi'.
One common and idiomatic solution to this problem is to capture the value of m at the time that the lambda is created by using it as the default argument of an optional parameter. You usually use a parameter of the same name so you don't have to change the body of the code:
for m in ('do', 're', 'mi'):     funcList.append(lambda m=m: callback(m)) 
                        The problem here is the m variable (a reference) being taken from the surrounding scope. Only parameters are held in the lambda scope.
To solve this you have to create another scope for lambda:
def callback(msg):     print msg  def callback_factory(m):     return lambda: callback(m)  funcList=[] for m in ('do', 're', 'mi'):     funcList.append(callback_factory(m)) for f in funcList:     f()   In the example above, lambda also uses the surounding scope to find m, but this time it's callback_factory scope which is created once per every callback_factory call.
Or with functools.partial:
from functools import partial  def callback(msg):     print msg  funcList=[partial(callback, m) for m in ('do', 're', 'mi')] for f in funcList:     f() 
                        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