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

相關文章
相關標籤/搜索