求值时间(Evaluation Time)
Python lambda函数的行为可能有点反直觉,例如在一些包含循环的情况中。要深入理解这些行为,需要搞清楚Python中的变量到底什么时候绑定的。
下面看看常规函数和lambda的例子。
1>>> def wrap(n):
2... def f():
3... print(n)
4... return f
5...
6>>> numbers = 'one', 'two', 'three'
7>>> funcs = []
8>>> for n in numbers:
9... funcs.append(wrap(n))
10...
11>>> for f in funcs:
12... f()
13...
14one
15two
16three
上面代码是常规函数,参数n是在第9行的时候求值并绑定的,也就是说这个wrap函数的返回值(f),被加入到funcs中的时候一定就已经确定了。
现在我们用lambda把上面的逻辑再撸一遍,看看它作什么妖。
1>>> numbers = 'one', 'two', 'three'
2>>> funcs = []
3>>> for n in numbers:
4... funcs.append(lambda: print(n))
5...
6>>> for f in funcs:
7... f()
8...
9three
10three
11three
结果大不同。变量n的值,在lambda真正执行的时候才求值。所以n的值是"three"。在第4行的lambda函数会生成一个闭包,而n作为一个自由变量,在运行时才绑定到这个闭包上。
要想解决这个晚绑定的问题,可以用下面的方式将自由变量(free variable)赋值到lambda的参数,这里的参数n的缺省值是变量n,而Python中缺省参数是早绑定的。
1>>> numbers = 'one', 'two', 'three'
2>>> funcs = []
3>>> for n in numbers:
4... funcs.append(lambda n=n: print(n))
5...
6>>> for f in funcs:
7... f()
8...
9one
10two
11three
划重点 - Python lambda函数对于参数的处理跟常规函数是一样的。例如上面的缺省参数的早绑定行为。如果你有点晕乎,将上面的lambda函数改写成这样 lambda x=n: print(x)
也可以。是不是容易理解一些?上面代码的第7行函数调用没有传递参数,所以会使用函数定义时绑定的值,也就是numbers数组中的元素值。
每天学一点,进步每一天~~
文中的例子来自 : https://realpython.com/python-lambda/