Lambda in a loop [duplicate] Lambda in a loop [duplicate] python python

Lambda in a loop [duplicate]


You need to bind d for each function created. One way to do that is to pass it as a parameter with a default value:

lambda d=d: self.root.change_directory(d)

Now the d inside the function uses the parameter, even though it has the same name, and the default value for that is evaluated when the function is created. To help you see this:

lambda bound_d=d: self.root.change_directory(bound_d)

Remember how default values work, such as for mutable objects like lists and dicts, because you are binding an object.

This idiom of parameters with default values is common enough, but may fail if you introspect function parameters and determine what to do based on their presence. You can avoid the parameter with another closure:

(lambda d=d: lambda: self.root.change_directory(d))()# or(lambda d: lambda: self.root.change_directory(d))(d)


This is due to the point at which d is being bound. The lambda functions all point at the variable d rather than the current value of it, so when you update d in the next iteration, this update is seen across all your functions.

For a simpler example:

funcs = []for x in [1,2,3]:  funcs.append(lambda: x)for f in funcs:  print f()# output:333

You can get around this by adding an additional function, like so:

def makeFunc(x):  return lambda: xfuncs = []for x in [1,2,3]:  funcs.append(makeFunc(x))for f in funcs:  print f()# output:123

You can also fix the scoping inside the lambda expression

lambda bound_x=x: bound_x

However in general this is not good practice as you have changed the signature of your function.


Alternatively, instead of lambda, you can use functools.partial which, in my opinion, has a cleaner syntax.

Instead of:

for d in directorys:    self.command["cd " + d] = (lambda d=d: self.root.change_directory(d))

it will be:

for d in directorys:    self.command["cd " + d] = partial(self.root.change_directory, d)

Or, here is another simple example:

numbers = [1, 2, 3]lambdas = [lambda: print(number)            for number in numbers]lambdas_with_binding = [lambda number=number: print(number)                         for number in numbers]partials = [partial(print, number)             for number in numbers]for function in lambdas:    function()# 3 3 3for function in lambdas_with_binding:    function()# 1 2 3for function in partials:    function()# 1 2 3