Python匿名函数--lambda

python 使用 lambda 来建立匿名函数。python

  • lambda只是一个表达式,函数体比def简单不少。
  • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  • lambda函数拥有本身的命名空间,且不能访问自有参数列表以外或全局命名空间里的参数。
  • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增长运行效率。

语法

lambda函数的语法只包含一个语句,以下:express

lambda [arg1 [,arg2,.....argn]]:expression 

以lambda x: x+1为例,首先,它是一个函数:闭包

def f(x):
return x+1

好,这个函数引用时须要传入一个参数,而且有一个返回值。这个参数通常是for x in L之类的传进来,或者直接调用f(3)。app

(1)先看第一个例子函数

f = lambda x: x**2
print(f(5)) # 25


结果是25,很easy,这里要说明的是lambda x: x**2是一个函数,你若是print(f)的获得的是一个函数的地址,记住它是一个函数。spa

(2)和append搭配、在for循环内部code

for x in range(5):
li.append(lambda x: x**2)
print(li[0](2)) # 4
print(li[1](3)) # 9

注:此处省略li = []的初始化代码,后续同样
li是一个list,可是list里面存的可不是数,而是函数地址,并且是5个x**2的函数,因此不管你是li[0](2)仍是li[1](2),结果都是4。通常状况下不会这样写程序,由于没什么用途。blog

这里说一下,看过一个程序这样写,猜想原做者是想让li在运算时append的是数据,或者是觉得这样可让li在调用时n的值不随x变,无论这样,这个程序实际效果和上面同样,x自己在变,n = x写不写没有区别,li内部仍然是5个同样的函数的地址。内存

for x in range(5):
li.append(lambda n=x: n**2)
print(li[0](2)) # 4
print(li[1](3)) # 9

总结一下:lambda在for循环内部,和append搭配时,for循环不是为了给函数传递参数,只是为了生成多个函数。generator

(3)只和append搭配

li.append(lambda x: x**2)
print(li[0](1)) # 1
print(li[0](3)) # 9
print(li[1](3)) # IndexError: list index out of range

这儿说的是另一种状况,程序中并无给出匿名函数lambda的参数,在调用时才会给。并且li仅仅append了一次,因此li内部也仅有一个函数地址。调用时就不会有li[1]这种状况。

补充一种它的变形,说明一下对于这种状况,参数赋初值并没有意义。

li.append(lambda x=5: x**2)
print(li[0](1)) # 1
print(li[0](3)) # 9
print(li[1](3)) # IndexError: list index out of range

(4)和append搭配、参数由for循环给出

举个栗子

li.append(lambda :x for x in range(10))
print(next(li[0])()) # 0
print(next(li[0])()) # 1
print(next(li[1])()) # IndexError: list index out of range

此处有大坑,首先你得认出来(lambda :x for x in range(10))这种形式可没有那么简单,这是产生一个生成器最简单的方法,它的返回值是一个generator,因此li内部就存了一个generator。还有此时的函数是没有参数的,等效为:

def f():
return x

有人会说这个函数有什么意义吗,是没什么意义,可是若是return x**2,其实仍是有些意义的。

(5)放在[]中、参数由for循环给出

li = [lambda :x for x in range(10)]
print(li[0]()) # 9
print(li[1]()) # 9

这个函数其实很差理解,首先别当作生成器了,跟它不要紧。
lambda :x仍然是一个函数(return x),在没有print(li[0]())以前它是不会被执行的,一旦运行print(li[0]()),就会输出x的值,那么x是多少呢,显然x在上一句程序里面已经变成9了,因此结果都是9,这里实际上是闭包的问题,想避免这个问题,程序就不能写这么简洁了。

for x in range(5):
def f():
return x**2
li.append(f())# instant run
print(li[0], li[1], li[2], li[3], li[4])

结果是0, 1, 4, 9, 16,是咱们想要的,有人会说这儿为何不把def f()简化一下呢?还真不能简化,比较结果便知:

for x in range(5):
li.append(lambda :x**2) # uninstant run
print(li[0](), li[1](), li[2](), li[3](), li[4]())
#16 16 16 16 16

看到区别了吧,f 是一个函数地址,而 f() 是一个函数被执行后的返回值,因此第一个程序能够获得每次循环的 x 值。

(6)lambda最经常使用:和map、reduce、filter等结合用
其实lambda最经常使用的仍是和map、reduce、filter这些高级函数结合使用,不过那个时候就把它当作一个函数,并且格式相对固定,具体使用就看高级函数的使用规则,较为简单,就不展开。

相关文章
相关标签/搜索