Thursday, September 02, 2010

Closure Snafu In Python

Python does not support closures. To use the value of a variable within a lambda expression, rebind the value to a locally defined variable. For instance
accept_set = set([1,2,3])
f = (lambda x, s=accept_set: x in s)
accept_set = set([4,5,6])
print filter(f,range(1,7))
will work as expected from a functional language (i.e. output [1, 2, 3]). But do it without that rebinding
accept_set = set([1,2,3])
f = (lambda x: x in accept_set)
accept_set = set([4,5,6])
print filter(f,range(1,7))
will yield [4, 5, 6] instead.

This is due to Python using pass by reference, and looking up values at run-time. Also, the lack of closures in general.

2 comments:

Mohammad said...

Interesting. I had thought that it had closures because I usually didn't rebind variables after defining the lambda. This is quite useful.

The_Laptop said...

I thought that was the case to, which was what prompted this discovery.

I was using a list of functions to perform a multiple-function filter. The results kept looking weird until I looked a little deeper into the problem.

So the design of Python has its priorities such that there should be nothing standing in the way of performing duck-typing, i.e. even when they support functional programming style, they support it such that it is consistent with Python's general laissez-faire attitude towards variables, worrying about it only during access time at run-time.

Another mildly confusing point will be the variable you use for looping; it is still possible to reference it and get the last value outside of the loop. But since most of us are good programmers, we hardly see this feature in action...