1

i have to create a list of functions, each pretty similar, but with a different constant.

for instance i want to have a list like "multiplication"

and i need hundreds of functions, so i used a for, the problem is that the functions that i have create multiply by the current value of "i", and not by the value that "i" had when the function has been declared

how do i get the desired result (like the firs list of function for instance)?

def main():

    #method one (working)

    multiplication = []

    multiplication.append(lambda z:z*0)
    multiplication.append(lambda z:z*1)
    multiplication.append(lambda z:z*2)
    multiplication.append(lambda z:z*3)

    # moltiplication: 2*4
    print(multiplication[2](4))
    #output: 8

    #method two (not working)

    multiplication_2 = []

    for i in range(4):
        multiplication_2.append(lambda z:z*i)

    #supposed to multiply 2*4 but multiply 4*i instead
    print(multiplication_2[2](4))
    #output: 12
    i = 22
    print(multiplication_2[2](4))
    #output: 88


if (__name__ == '__main__'):
    main()

i know that i can pass an argument to the function, but this is only an example that can lead me to solve my problem. and in the real use case the functions need to be created like this

Luca
  • 55
  • 4
  • See here: [Why do lambdas defined in a loop with different values all return the same result ?](https://docs.python.org/3/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result) – BcK Feb 01 '22 at 19:47
  • The "correct" way to handle this is to use a *factory function*, which will create a new enclosing scope. So, `def func_maker(i): return lambda z: z*i` and then in your loop `multiplication_2.append(func_maker(i))` – juanpa.arrivillaga Feb 01 '22 at 19:49

1 Answers1

0

The trick is to ensure you evaluate i at the time the lambda is defined, not inside the body of the lambda (where it'll be evaluated only when the lambda is called):

multiplication_2 = []

for i in range(4):
    multiplication_2.append(lambda z, i=i: z * i)

print(multiplication_2[2](4))
#output: 8
i = 22
print(multiplication_2[2](4))
#output: 8

The i=i "trick" works because the right hand side is evaluated (so it gets the current value of i in the loop) and is then used as the default argument value for the i parameter inside the lambda (shadowing whatever new value i might have in the outer scope).

You can give the parameter a different name from the default argument if that's less confusing, e.g.:

multiplication = [(lambda z, j=i: z * j) for i in range(4)]
print([f(4) for f in multiplication])  # [0, 4, 8, 12]

In the above example j is the parameter inside the lambda, and each lambda has a different default value for j that is equivalent to the value that i had at the time the lambda was created.

Samwise
  • 68,105
  • 3
  • 30
  • 44