python 使用 lambda 來建立匿名函數。python
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這些高級函數結合使用,不過那個時候就把它當作一個函數,並且格式相對固定,具體使用就看高級函數的使用規則,較爲簡單,就不展開。