Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python lambda doesn't remember argument in for loop [duplicate]

I'm working with python and trying to isolate a problem I had with lambda functions.

From the following code I was expecting to create two lambda functions, each getting a different x, and the output should be

1
2

but the output is

2
2

Why? And how can I make two different functions? Using def?

def main():
    d = {}
    for x in [1,2]:
        d[x] = lambda: print(x)

    d[1]()
    d[2]()

if __name__ == '__main__':
    main()
like image 999
user985366 Avatar asked Jul 30 '12 14:07

user985366


People also ask

Can Lambda take two arguments Python?

A lambda function can take any number of arguments, but can only have one expression.

Can Lambda take multiple arguments?

A lambda function is an anonymous function (i.e., defined without a name) that can take any number of arguments but, unlike normal functions, evaluates and returns only one expression.

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. Instead, you need to use the write method on sys.

Can Python lambda have default arguments?

A Python lambda function behaves like a normal function in regard to arguments. Therefore, a lambda parameter can be initialized with a default value: the parameter n takes the outer n as a default value. The Python lambda function could have been written as lambda x=n: print(x) and have the same result.


3 Answers

The body of the lambda in your code references the name x. The value associated with that name is changed on the next iteration of the loop, so when the lambda is called and it resolves the name it obtains the new value.

To achieve the result you expected, bind the value of x in the loop to a parameter of the lambda and then reference that parameter, as shown below:

def main():
    d = {}
    for x in [1,2]:
        d[x] = lambda x=x: print(x)

    d[1]()
    d[2]()


if __name__ == '__main__':
    main()

>>> 
1
2
like image 84
applicative_functor Avatar answered Nov 01 '22 06:11

applicative_functor


Looks like work for partial.

from functools import partial 
def main():
    d = {}
    for x in [1,2]:
        d[x] = partial(lambda x: print(x), x=x)

    d[1]()
    d[2]()


if __name__ == '__main__':
    main()
like image 36
Nikolay Fominyh Avatar answered Nov 01 '22 07:11

Nikolay Fominyh


This will fix it. It is because the x is directly bound to the lambda.

def create_lambda(x):
    return lambda : print(x)

def main():
    d = {}
    for x in [1,2]:
        d[x] = create_lambda(x)

    d[1]()
    d[2]()


if __name__ == '__main__':
    main()
like image 4
ThirdOne Avatar answered Nov 01 '22 06:11

ThirdOne