3

I am in need of creating functions (a lot) and storing inside an array or list. I tried using list comprehensions for generating functions (like the code shown below, indeed a simple case).

f = [lambda x: x*i for i in range(0,3)]

which gives

f[0](1) = 2       # expected 0
f[1](1) = 2       # expected 1
f[2](1) = 2       # expected 2 (no prblm with last case)

But instead of using iterators (like list comprehensions) to generate functions, if I write functions explicitly inside a list(defining each function), it works fine.

So, is there anything wrong with the above code(which uses iterators to generate anonymous functions)?

martineau
  • 119,623
  • 25
  • 170
  • 301
Rajasekar
  • 39
  • 3

2 Answers2

3

I believe this variant of the syntax will give you what you want:

f = [lambda x, i=n: x * i for n in range(0, 3)]

EXAMPLES

>>> f[0](1)
0
>>> f[1](1)
1
>>> f[2](1)
2
>>> 

I believe what @user2357112 is leading you towards is the variation:

from functools import partial

f = [partial(lambda x, i: x * i, i=n) for n in range(0, 3)]

which may not be easy to tease out of the cited duplication page.

cdlane
  • 40,441
  • 5
  • 32
  • 81
2

The inside of your lambda function is evaluated when you call the function, not when you create the function. At this point point the value of i is 2. You can verify this by running:

>>> f = [lambda x: x*i for i in range(0,3)]
>>> i
2

As cdlane pointed out in his answer, you can fix this by storing the values from the range() statement into a default parameter on your lambda function:

>>> f = [lambda x, i=i: x*i for i in range(0,3)]
>>> f[0](1)
0
>>> f[1](1)
1
>>> f[2](1)
2

This works because unlike the function body, the function definition is evaluated when you create the function.

larsks
  • 277,717
  • 41
  • 399
  • 399