Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused by lexical closure in list comprehension

Tags:

python

l = [1, 2, 3]
a,b,c = [lambda: n*n for n in l]
a()  #=> 9
b()  #=> 9
c()  #=> 9

Why is this? I expected a(), b(), c(), to be 1, 4, and 9.

like image 567
Des Avatar asked Jan 25 '13 03:01

Des


1 Answers

n isn't in a local closure of the functions.

try

a, b, c = [lambda n=n: n*n for n in l]

This "abuse" of the default parameter causes a local variable called n to be created for each function

Here is another way to create a closure in Python2

>>> L=[1, 2, 3]
>>> def fgen():
...     local_n = global_n
...     def f():
...         return local_n * local_n
...     return f
>>> a, b, c = [fgen() for global_n in L]
>>> a()
1
>>> b()
4
>>> c()
9

It won't work in Python3 though because the loop var in the list comprehension isn't leaked into the global scope

Python3 does a better job of preventing us using a global in the function, so you need to pass a parameter if you want to use a list comprehension

>>> L=[1, 2, 3]
>>> def fgen(param_n):
...     local_n = param_n
...     def f():
...         return local_n * local_n
...     return f
... 
>>> a, b, c = [fgen(n) for n in L]
>>> a()
1
>>> b()
4
>>> c()
9
>>> 
like image 129
John La Rooy Avatar answered Sep 17 '22 04:09

John La Rooy