470,604 Members | 2,286 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,604 developers. It's quick & easy.

can this be done without eval/exec?

Hello group,
lst=[]
for i in range(10): .... lst.append(eval("lambda:%i" % i))
.... lst[0]() 0 lst[1]() 1 lst[9]() 9 lst=[]
for i in range(10): .... exec "tmp = lambda:%i" % i # assignment is not expression
.... lst.append(tmp)
.... lst[0]() 0 lst[1]() 1 lst[9]() 9
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

are there other solutions to this problem
without use of eval or exec?

Regards, Daniel
Apr 27 '06 #1
4 1355
On 4/26/06, Schüle Daniel <uv**@rz.uni-karlsruhe.de> wrote:
Hello group,
>>> lst=[]
>>> for i in range(10): ... lst.append(eval("lambda:%i" % i))
... >>> lst[0]() 0 >>> lst[1]() 1 >>> lst[9]() 9 >>> >>> lst=[]
>>> for i in range(10): ... exec "tmp = lambda:%i" % i # assignment is not expression
... lst.append(tmp)
... >>> lst[0]() 0 >>> lst[1]() 1 >>> lst[9]() 9 >>>
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

are there other solutions to this problem
without use of eval or exec?

Using a factory function & closures instead of lambda:
def maker(x): .... def inner_maker():
.... return x
.... return inner_maker
.... lst = []
for i in range(10): .... lst.append(maker(i))
.... lst[0]() 0 lst[5]() 5 lst[9]() 9


Regards, Daniel
--
http://mail.python.org/mailman/listinfo/python-list

Apr 27 '06 #2
>> are there other solutions to this problem
without use of eval or exec?


Using a factory function & closures instead of lambda:

def a(x): .... def b():
.... return x
.... return b
.... lst=[]
for i in range(10): .... lst.append(a(i))
.... lst[0]() 0 lst[1]() 1 lst[9]() 9
yes this works
I was playing a little more with this idea
and got into the next trouble :)
cnt=0
def a(): .... def b():
.... return cnt
.... global cnt
.... cnt += 1
.... return b
.... lst=[]
for i in range(10): .... lst.append(a())
.... lst[0]() 10 lst[1]() 10
I figured out what was wrong, here is corrected version
cnt = 0
def a(): .... global cnt
.... tmp = cnt
.... def b():
.... return tmp
.... cnt += 1
.... return b
.... lst=[]
for i in range(10): .... lst.append(a())
.... lst[0]() 0 lst[1]() 1


Regards, Daniel
Apr 27 '06 #3
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
Apr 27 '06 #4
Kent Johnson schrieb:
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


many thanks for the explaination,
it look much simpler than my solutions too

Daniel
Apr 27 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by Ido.Yehieli | last post: by
3 posts views Thread by Jens | last post: by
6 posts views Thread by dave.g1234 | last post: by
10 posts views Thread by TheSaint | last post: by
6 posts views Thread by Stef Mientki | last post: by
16 posts views Thread by Fett | last post: by
reply views Thread by Jean-Paul Calderone | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.