How to generate a list of different lambda functions with list comprehension?

前端 未结 4 449
有刺的猬
有刺的猬 2021-01-13 23:00

This question is distilled from the original application involving callback functions for Tkinter buttons. This is one line that illustrates the behavior.

lam

4条回答
  •  余生分开走
    2021-01-13 23:11

    Use a parameter with default value to bind the current value of i to a local variable. When the lambda gets called without an argument, the local variable i is assigned the default value:

    In [110]: lambdas = [lambda i=i: i for i in range(3)]
    
    In [111]: for lam in lambdas:
       .....:       print(lam())
       .....: 
    0
    1
    2
    

    When i is not a local variable, Python looks up its value in the enclosing scope. The value that is found is the last value i attained in the for-loop of the list comprehension. That is why, without the parameter with default value, each lambda returns 2 since the for-loop has completed by the time the lambdas get called.


    Another common approach to solving this problem is to use a closure -- a function that can refer to environments that are no longer active such as the local namespace of an outer function, even after that function has returned.

    def make_func(i):
        return lambda: i
    
    lambdas = [make_func(i) for i in range(3)]
    for lam in lambdas:
        print(lam())
    

    prints

    0
    1
    2
    

    This works because when lam() gets called, since the i in the lambda function's body is not a local variable, Python looks for the value of i in the enclosing scope of the function make_func. Its local namespace is still accessible to the closure, lam, even though make_func has already completed. The value in that local namespace is the value which was passed to make_func, which is, happily, the desired value of i.


    As already mentioned by mkrieger1, another way to create a new function with some argument values already supplied is to use functools.partial:

    lambdas = [functools.partial(lambda x: x, i) for i in range(3)]
    

提交回复
热议问题