can this be done without eval/exec?

Kent Johnson kent at kentsjohnson.com
Thu Apr 27 09:07:25 EDT 2006


Schüle Daniel wrote:
> and now the obvious one (as I thought at first)
> 
>  >>> lst=[]
>  >>> for i in range(10):
> ...     lst.append(lambda:i)
> ...
>  >>> lst[0]()
> 9
>  >>> i
> 9
>  >>>
> 
> I think I understand where the problem comes from
> lambda:i seems not to be fully evalutated
> it just binds object with name i and not the value of i
> thus lst[0]() is not 0

The problem is that variables in closures are not bound until the 
variable goes out of scope. So each lambda is bound to the final value of i.
> 
> are there other solutions to this problem
> without use of eval or exec?

The workaround is to use a default argument to bind the current value of i:
In [1]: lst = []

In [2]: for i in range(10):
    ...:     lst.append(lambda i=i: i)
    ...:
    ...:

In [3]: lst[0]()
Out[3]: 0

In [4]: lst[5]()
Out[4]: 5

A list comp makes this IMO cleaner:
In [5]: lst = [ lambda i=i: i for i in range(10) ]

In [6]: lst[0]()
Out[6]: 0

In [7]: lst[5]()
Out[7]: 5

Kent



More information about the Python-list mailing list