a strange usage for lambda in python

Viewed 102

I encounter a part of code as follows, where workers is a list of class object:

worker_threads = []
for worker in workers:
    worker_fn = lambda worker=worker: worker.run(sess, coord, FLAGS.t_max)
    t = threading.Thread(target=worker_fn)
    t.start()
    worker_threads.append(t)

Normally I expect the syntax for lambda is lambda x : func(x), but in here what is the worker=worker used for ?

3 Answers

It's being done to bind the value of worker inside the lambda. Here's a simplified example of this technique:

>>> thunks = [lambda: i for i in range(5)]
>>> [thunk() for thunk in thunks]
[4, 4, 4, 4, 4]
>>>
>>> thunks = [lambda i=i: i for i in range(5)]
>>> [thunk() for thunk in thunks]
[0, 1, 2, 3, 4]

With the expression lambda: i, i is evaluated at the time the lambda is called, not when it is defined. Hence in the first example, the results from all of the thunks are 4 because that's the value that i has at the end of the range(5) loop.

With the expression lambda i=i: i, now the value of i is being evaluated immediately within the loop in order to provide the default value of the i parameter. This allows each thunk to capture a unique value of i.

The concept might be more clear if the parameter is given a different name instead of shadowing i:

>>> thunks = [lambda n=i: n for i in range(5)]
>>> [thunk() for thunk in thunks]
[0, 1, 2, 3, 4]

In your example, the lambda could be written as:

worker_fn = lambda w=worker: w.run(sess, coord, FLAGS.t_max)

This behaves the same as the worker=worker: worker.run... expression in your code, but might make it a little more clear that the purpose of the expression is to take the current value of worker in the loop and pass it into the body of the lambda as a parameter.

Not an answer but this works:

t = list()
for i in [1,2,3,4]:
  func = lambda x=i: x*x
  t.append(func)

print(t[1]) 
# <function <lambda> at 0x7fdba6e6d790>
print(t[1]()) 
# 4

So you can bind your variables/parameters to a lambda function

It is explained here

Think about it like this:

def f(x):
    print(x)

f('yes')

>>> 'yes'

x = 'no'
def f(x=x):
    print(x)

f()
>>> 'no'

f('yes')
>>> 'yes'

Or in lambda world:


f = lambda x:print(x)

f('yes')

>>> 'yes'

x = 'no'
f = lambda x=x: print(x)

f()
>>> 'no'

f('yes')
>>> 'yes'

So to make the answer WHY explicit for the commenters here, doing this lets each lambda be defined with a different default x value.

Related