1

I saw this below piece of code in a tutorial and wondering how it works. Generally, the lambda takes a input and returns something but here it does not take anything and still it works.

    >>> for i in range(3):
...     a.append(lambda:i)
...
>>> a
[<function <lambda> at 0x028930B0>, <function <lambda> at 0x02893030>, <function
 <lambda> at 0x028930F0>]
1
  • 2
    That depends on how you define "works." What do you want it to do? Commented Jun 16, 2015 at 0:43

4 Answers 4

1

lambda:i defines the constant function that returns i.

Try this:

>>> f = lambda:3
>>> f()

You get the value 3.

But there's something more going on. Try this:

>>> a = 4
>>> g = lambda:a
>>> g()

gives you 4. But after a = 5, g() returns 5. Python functions "remember" the environment in which they're executed. This environment is called a "closure". By modifying the data in the closure (e.g. the variable a in the second example) you can change the behavior of the functions defined in that closure.

Sign up to request clarification or add additional context in comments.

Comments

1

In this case a is a list of function objects defined in the loop.

Each of which will return 2.

>>> a[0]()
2

To make these function objects remember i values sequentially you should rewrite the code to

>>> for i in range(3):
...     a.append(lambda x=i:x)
... 

that will give you

>>> a[0]()
0
>>> a[1]()
1
>>> a[2]()
2

but in this case you get side effect that allows you to not to use remembered value

>>> a[0](42)
42

Comments

0

I'm not sure what you mean by "it works". It appears that it doesn't work at all. In the case you have presented, i is a global variable. It changes every time the loop iterates, so after the loop, i == 2. Now, since each lambda function simply says lambda:i each function call will simply return the most recent value of i. For example:

>>> a = []
>>> for i in range(3):
    a.append(lambda:1)
>>> print a[0]()
2
>>> print a[1]()
2    
>>> print a[2]()

In other words, this does not likely do what you expect it to do.

Comments

0

lambda defines an anonymous inline function. These functions are limited compared to the full functions you can define with def - they can't do assignments, and they just return a result. However, you can run into interesting issues with them, as defining an ordinary function inside a loop is not common, but lambda functions are often put into loops. This can create closure issues.

The following:

>>> a = []
>>> for i in range(3):
...     a.append(lambda:i)

adds three functions (which are first-class objects in Python) to a. These functions return the value of i. However, they use the definition of i as it existed at the end of the loop. Therefore, you can call any of these functions:

>>> a[0]()
2
>>> a[1]()
2
>>> a[2]()
2

and they will each return 2, the last iteration of the range object. If you want each to return a different number, use a default argument:

>>> for i in range(3):
...     a.append(lambda i=i:i)

This will forcibly give each function an i as it was at that specific point during execution.

>>> a[0]()
0
>>> a[1]()
1
>>> a[2]()
2

Of course, since we're now able to pass an argument to that function, we can do this:

>>> b[0](5)
5
>>> b[0](range(3))
range(0, 3)

It all depends on what you're planning to do with it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.