Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating lambda inside a loop [duplicate]

Tags:

python

Possible Duplicate:
What do (lambda) function closures capture in Python?
lambda function don't closure the parameter in Python?

I am trying to create lambdas inside a loop that iterates over a list of objects:

lambdas_list = [] for obj in obj_list:    lambdas_list.append(lambda : obj.some_var) 

Now, if I iterate over the lambdas list and call them like this:

for f in lambdas_list:     print f() 

I get the same value. That is the value of the last obj in obj_list since that was the last variable in the block of the list iterator. Any ideas fn a good (pythonic) rewrite of the code to make it work?

like image 761
Meir Avatar asked Sep 25 '11 14:09

Meir


People also ask

Can I use for loop in lambda?

Since a for loop is a statement (as is print , in Python 2. x), you cannot include it in a lambda expression.

Can lambda functions be nested?

A lambda function inside a lambda function is called a nested lambda function. Python allows lambda nesting, i.e., you can create another lambda function inside a pre-existing lambda function. For nesting lambdas, you will need to define two lambda functions – an outer and an inner lambda function.

Is lambda expression faster than for loop?

The answer is it depends. I have seen cases where using a lambda was slower and where it was faster. I have also seen that with newer updates you get more optimal code.

Can lambda return 2 values?

That's not more than one return, it's not even a single return with multiple values. It's one return with one value (which happens to be a tuple).


2 Answers

Use this line instead:

lambdas_list.append(lambda obj=obj: obj.some_var) 
like image 70
Vaughn Cato Avatar answered Oct 13 '22 08:10

Vaughn Cato


You either have to capture the variable using default assignments

lambdas_list = [ lambda i=o: i.some_var for o in obj_list ] 

or, use closures to capture the variable

lambdas_list = [ (lambda a: lambda: a.some_var)(o) for o in obj_list ] 

In both cases the key is to make sure each value in the obj_list list is assigned to a unique scope.

Your solution didn't work because the lexical variable obj is referenced from the parent scope (the for).

The default assignment worked because we reference i from the lambda scope. We use the default assignment to make "passing" the variable implicit by making it part of the lambda definition and therefore its scope.

The closure solution works because the variable "passing" is explicit, into the outer lambda which is immediately executed, thus creating the binding during the list comprehension and and returning the inner lambda which references that binding. So when the inner lambda actually executes it will be referencing the binding created in the outer lambda scope.

like image 37
dietbuddha Avatar answered Oct 13 '22 08:10

dietbuddha