0

I would like to create a list of function using list comprehension/for loop

def multiplier():
    return [(lambda x: x*0),(lambda x: x*1),(lambda x: x*2),(lambda x: x*3)]

such that

[m(2) for m in multiplier()]
[m(3) for m in multiplier()]

will output [0,2,4,6] and [0,3,6,9] respectively

however when I attempt to do so:

def multiplier():
    return [lambda x:i*x for i in range(4)]

or

def multiplier():
    result = [] 
    for i in range(4):
        result.append(lambda x:x*i)
   return result

or

def multiplier():
    result = [] 
    for i in range(4):
        def m(x): return x*i 
        result.append(m)
    return result   

The following:

[m(2) for m in multiplier()]
[m(3) for m in multiplier()]

will output [6,6,6,6] and [9,9,9,9] respectively.

How do I create this list of functions without manually typing one by one! Any explanation? Thanks!

Adam Ilyas
  • 13
  • 1
  • 3

3 Answers3

1

You need to supply i as argument to bind to the i from range:

def multiplier():
    return [lambda x, i=i:i*x for i in range(4)]

print([m(2) for m in multiplier()])
print([m(3) for m in multiplier()])

Output:

[0, 2, 4, 6]
[0, 3, 6, 9]

In your case i will always be the last value of the range loop, because the function looks for the i when it is called. Providing the i as keyword actually makes the i default argument for the created function at creation time.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
0

Consider using functools.partial with a dictionary:

from functools import partial

def multiplier(x, n):
    return x * n

m = {k: partial(multiplier, n=k) for k in range(0, 4)}

[m[k](2) for k in m]  # [0, 2, 4, 6]
[m[k](3) for k in m]  # [0, 3, 6, 9]
jpp
  • 159,742
  • 34
  • 281
  • 339
-1

It worked for me replacing the '[' with '(' like

(lambda x:i*x for i in range(4))

and I believe it has to do with the fact that lists are mutable while tuples are not.

Alex
  • 44
  • 4
  • That doesn't actually work either, but it might look like it works if you always iterate through the function objects and call them in turn (since you're iterating through the range at the same time). The `i` variable is still only closed over once. – Daniel Pryden Feb 20 '18 at 16:51
  • Also, Python lists are most definitely mutable, not immutable! And even tuples, which *are* immutable, are only shallowly immutable: it's perfectly possible to have a tuple of objects that contain or close over mutable state. – Daniel Pryden Feb 20 '18 at 16:53
  • Hi this actually works! Any explanation of how a tuple being immutable helps in this case? – Adam Ilyas Feb 20 '18 at 17:02
  • Frankly my assumption was wrong due to the fact that the resulting expresion is a generator, instead of a tuple, which behaves like an iterator. – Alex Feb 20 '18 at 17:14