2

For the purpose of this post, I've handcrafted a silly example, but what I'm interested in, is the underlying concept, so alternative solutions to this particular problem are not what I'm looking for. I've tried multiple times to find any similar thread but honestly, its hard to word this particular question. So here we go...

The following code:

lambdas = []
for i in range(5):
    lambdas.append(lambda:i)

for l in lambdas:
    print(l())

yields:

4
4
4
4
4

Which means, each element of the lambda list will always return the current value of i

My cheap workaround is:

lambdas = []
for i in range(5):
    lambdas.append(eval("lambda:{}".format(i)))

for l in lambdas:
    print(l())

which yields the desired:

0
1
2
3
4

However it is my understanding that it is best to avoid eval statements whenever possible.

So my question is: Is there a better workaround to achieve the same result (while still using lambda expressions)?

J3STER
  • 1,027
  • 2
  • 11
  • 28
  • 1
    The cleanest way is to use a factory function forcing the closure to capture the value you want. So, `def create_func(i): return lambda :i` then, in your loop, `for i in range(5): funcs = create_func(i)`. – juanpa.arrivillaga Aug 01 '20 at 10:42
  • You can use a lambda to a similar effect as above, so in your loop, do: `lambdas.append((lambda x: lambda:x)(i))`, but that's always messy to my eyes. There is also the hacky albeit somewhat idiomatic way of using a keyword argument, `lambdas.append(lambda i=i: i)`, but I personally don't like that – juanpa.arrivillaga Aug 01 '20 at 10:42
  • 1
    WHOOPs, I mean, `def create_func(i): return lambda :i`, then the loop should be: `for i in range(5): lambdas.append(create_func(i))` Note, a `lambdas` isn't a great name, a lambda isn't a type in Python, it's an alternative syntax, an expression, that creates a function object, but it's the same type of object as function objects created with full, function definition statements, `def func(): pass` then: `print(type(func) is type(lambda:None))` – juanpa.arrivillaga Aug 01 '20 at 10:51

1 Answers1

1

You must capture the i:

lambdas = []
for i in range(5):
    lambdas.append(lambda i=i:i)
thebjorn
  • 26,297
  • 11
  • 96
  • 138