简体   繁体   中英

How to define a list of non-constant functions in a loop with lambda functions?

Let's say that I want to create a list of functions funclist , such that the fonctions of this list behave that way:

funclist[0](x) = 0
funclist[1](x) = x
funclist[2](x) = 2*x
funclist[3](x) = 3*x

Assuming that the list is too long (say of size 100) to define those functions one-by-one, a natural way to write this would be:

funclist = []
for k in range(100):
    f = lambda x: k*x
    funclist.append(f)

The problem is that this approach does not work, because of the way Python interprets local variables within function definitions. This is a problem I saw coming back often on this website, for instance here or here . Unfortunately, those users want to define constant functions, so the proposed solution (which is to define a local copy of the iterable variable k) do not work for me (it is also the same solution proposed in the Python FAQ ). For instance, the following syntax does not work:

funclist = []
for k in range(100):
    f = lambda local_k=k, x: local_k*x
    funclist.append(f)

A solution I found is to do:

funclist = []
for k in range(10):
    def f(x, product_factor=k): return x*product_factor
    funclist.append(f)

which works as I want. I could also achieve the same result with the partial function:

from functools import partial 

def product(x,product_factor): return x*product_factor
funclist = []
for k in range(10):
    funclist.append( partial(product, product_factor=k) )

So my question is: is there any way to achieve this result with lambda functions only? Or the fact that I have a "moving parameter" dooms me to define in a way or an other a function of two variables? Let me precise that I am asking this because I am trying to understand better how functions and currying work in Python.

Your lambda approach does not work because you have a keyword argument before a positional one. Just flip the order as you did in the working solutions:

funclist = [(lambda x, local_k=k: local_k*x) for k in range(100)]

>>> funclist[3](8)
24
>>> funclist[5](9)
45

The initial problem is that k was only evaluated one time, at the end of the loop, while here the function creation, the call to get_function, triggers the evaluation of k every time.

Of course your solution with a default argument also works, it's apparently the most common solution for this problem

Now you said it didn't work with the lamdba, it's simply because you put the default argument first:

funclist = []
for k in range(100):
    f = lambda  x, local_k=k,: local_k*x
    funclist.append(f)


print(funclist[10](3)) #30
print(funclist[99](3)) # 297
print(funclist[0](3)) # 0

works just fine

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM