看python cookbook时候被这个问题困扰然后就花了不少时间在这上面
首先了解lambda函数,又被称为匿名函数
- lamda (参数):返回值表达式
- 参数在传入时候也可以设置默认值
- 要注意的一点是,
lambda
函数的参数是在每次调用时候传入,并不是在定义lambda
函数时就被传入 - 所有的函数都是如此,即在执行时候才会传入值,而不是定义时
先来看两个,我一直在想为什么第一个输出的全都是4
func = [lambda x: x + n for n in range(5)]
for f in func:
print(f(0))
4
4
4
4
4
funcs = [lambda x, n=n: x + n for n in range(5)]
for f in funcs:
print(f(0))
0
1
2
3
4
解答
闭包:闭包是由函数及其相关的引用环境组合而成的实体
结合例子来看,lambda x: x + n
和lambda x, n=n: x + n
就是一个在for循环中的闭包函数,其执行过程类似以下代码:
def f1(x):
flist = []
for n in range(5):
def add():
return x + n
flist.append(add)
return flist
for f in f1(0):
print(f())
def f2(x):
flist = []
for n in range(5):
def add(n1=n):
return x + n1
flist.append(add)
return flist
for f in f2(0):
print(f())
小知识
这里我插入另一个小知识点,调用函数时候加不加括号的区别
知道的朋友就直接跳过啦
f = func
将func这一函数对象赋予f
f = func()
函数执行,将执行结果赋予f
比如上面的f1
,我将其稍作修改,其结果会完全不同
def f1(x):
flist = []
for n in range(5):
def add():
return x + n
flist.append(add()) # 将add()执行的结果返回,分别为0,1,2,3
return flist
for f in f1(0):
print(f) # 这时候我们只能用f而不是f(),因为此时f不是函数对象了,而是一个值
回归正题
结合以下几个特性:
- python中循环的值在循环结束后不被销毁而是继续存在并且可以被调用
- 函数在执行时才传入参数
- 带括号的函数才是被执行的,不带括号则是引用该函数对象
对于func = [lambda x: x + n for n in range(5)]
,其执行过程见下图
而对于lambda x, n=n: x + n for n in range(5)
它的不同之处在于在其内部的n指向的是当前循环的n值
这样比较拗口,改写为lambda x, n1=n: x + n1 for n in range(5)
这样就清晰得多了
结束
以上,有的时候思考一下编程中的这种小陷阱虽然挺容易让人崩溃的,但只要想通了其中的逻辑,就很明了了。
网友评论