470,604 Members | 2,286 Online

# can this be done without eval/exec?

Hello group,
lst=[]
for i in range(10): .... lst.append(eval("lambda:%i" % i))
.... lst() 0 lst() 1 lst() 9 lst=[]
for i in range(10): .... exec "tmp = lambda:%i" % i # assignment is not expression
.... lst.append(tmp)
.... lst() 0 lst() 1 lst() 9
and now the obvious one (as I thought at first)
lst=[]
for i in range(10): .... lst.append(lambda:i)
.... lst() 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() 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 >>> lst() 1 >>> lst() 9 >>> >>> lst=[]
>>> for i in range(10): ... exec "tmp = lambda:%i" % i # assignment is not expression
... lst.append(tmp)
... >>> lst() 0 >>> lst() 1 >>> lst() 9 >>>
and now the obvious one (as I thought at first)
>>> lst=[]
>>> for i in range(10): ... lst.append(lambda:i)
... >>> lst() 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() 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 lst() 5 lst() 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 lst() 1 lst() 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() 10 lst() 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 lst() 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() 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() 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 : lst = []

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

In : lst()
Out: 0

In : lst()
Out: 5

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

In : lst()
Out: 0

In : lst()
Out: 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()

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() 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 : lst = []

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

In : lst()
Out: 0

In : lst()
Out: 5

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

In : lst()
Out: 0

In : lst()
Out: 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.