What's going on with the lambda expression in this python function?

前端 未结 4 1441
甜味超标
甜味超标 2020-12-19 11:53

Why does this attempt at creating a list of curried functions not work?

def p(x, num):
    print x, num

def test():
    a = []
    for i in range(10):
             


        
相关标签:
4条回答
  • 2020-12-19 12:00

    In Python, variables created in loops and branches aren't scoped. All of the functions you're creating with lambda have a reference to the same i variable, which is set to 9 on the last iteration of the loop.

    The solution is to create a function which returns a function, thus scoping the iterator variable. This is why the functools.partial() approach works. For example:

    def test():
        def makefunc(i):
            return lambda x: p(i, x)
        a = []
        for i in range(10):
            a.append(makefunc(i))
        return a
    
    0 讨论(0)
  • 2020-12-19 12:03

    I was always confused as to why this doesn't work. Thanks for the explanation, 'a paid nerd'. I personally prefer this solution:

    for i in range(10):
        a.append(lambda num, val_i=i: p (val_i, num))
    

    Note the val_i=i default argument of the lambda that enables to capture the instantaneous value of i during the loop whilst still effectively making lambda a function of 1 variable. (BTW: changed your x into num to match p's definition.) I like it better because:

    1. it is very close to the original idea and avoids having to define a new named function, precisely the purpose of a lambda...
    2. avoids importing functools
    3. and avoids imbricating lambdas...

    Just did a search and found more detailed explanations for the same problem there: Scope of python lambda functions and their parameters

    0 讨论(0)
  • 2020-12-19 12:10

    I asked a similar question, and got two answers. One basically the same as the accepted answer here, and the other which is less clear but slightly more succint.

    Dynamically creating a menu in Tkinter. (lambda expressions?)

    0 讨论(0)
  • 2020-12-19 12:21

    Well you can also bind the i to an outer lambda for the lazy.

    def p(x, num):
        print x, num
    
    def test():
        a = []
        for i in range(10):
            a.append((lambda i :lambda x: p (i, x))(i))
        return a
    
    0 讨论(0)
提交回复
热议问题