Python closures oddity

So today, I came across some weird code.

def foo(val):
    print val

lambda_list = [ lambda: foo(i) for i in xrange(3) ]
for lambda__ in lambda_list:

Don’t peek. Try to predict the output.


Surprising, isn’t it? I was certainly surprised to see the output come out as


Why’s this happening?

Well, it turns out that python closes on names, and not on values. What that means is, the value of i in our code is looked up only when the lambda__() function gets actually called within the for loop.


1. Just pass in the value of i as a parameter to the function. Unfortunately, the problem is, we are calling the function as lambda__() without any parameters. But default arguments would work nicely in this case.

lambda_list = [ lambda i=i: foo(i) for i in xrange(3) ]

2. Use functools.partial to wrap the function and the argument in, and then call it later

lambda_list = [ functools.partial(foo, i) for i in xrange(3) ]

3. If you are a closeted Javascript programmer, you could also do this…

lambda_list = [ (lambda i: (lambda: foo(i)))(i) for i in xrange(3) ]  

But seriously, please don’t do this, its terribly unreadable.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s