1. 程式人生 > >lambda函式詳細介紹(Python)

lambda函式詳細介紹(Python)

定義

在Python中,除了使用def關鍵字宣告普通函式外,還提供了一種使用表示式生成函式物件的形式。由於它與LISP語言中的一個工具很相似,所以稱為lambda。

lambda函式也叫匿名函式,即沒有具體名稱的函式,它允許快速定義單行函式,可以用在任何需要函式的地方。

lambda的語法形式如下:
  lambda arg1, arg2, …, argN : expression
首先是關鍵字lambda;隨後是一個或多個引數,其形式與用def定義函式的引數形式類似;緊跟的是一個冒號;最後是一個表示式,表示式使用的引數需要在冒號左邊進行定義,表示式的結果即是該匿名函式的結果。
lambda語句構建的其實是一個函式物件,其示例如下所示:

>>> g = lambda x: x**2
>>> g
<function <lambda> at 0x7f36cba80c08>

與def的聯絡和區別

聯絡

由lambda表示式所返回的函式物件與由def建立並複製後的函式物件工作起來是完全一樣的。
用def定義的求某個數的平方的函式f的程式碼如下:

>>> def f(x):
...     return x**2
... 
>>> f(4)
16

可使用lambda實現上述函式的功能

>>> g = lambda
x: x**2 >>> g(4) 16

預設引數也能夠在lambda引數中使用,就像在def中使用一樣。

>>> x = (lambda a="hello", b=",", c="world": a + b + c)
>>> x()
'hello,world'
>>> x("hi")
'hi,world'

在lambda主體中的程式碼與在def內的程式碼一樣,都遵循相同的作用域查詢法則。lambda表示式引入的一個本地作用域更像一個巢狀的def語句,將會自動從上層函式中、模組中以及內建作用域中(通過LEGB法則)查詢變數名。

>>> def test(title="Sir"):
...     action =  (lambda x: title + ' ' + x)
...     return action
... 
>>> act = test()
>>> act('robin')
'Sir robin'

區別

lambda和def具有如下區別:

  1. def定義的普通函式是有函式名稱的,而lambda定義的函式並沒有函式名稱,因此也被稱為匿名函式。
  2. lambda會返回一個函式物件,但不會為這個物件賦予一個識別符號,而def則會把函式物件賦值給一個變數即函式名。
  3. lambda只是一個表示式,而def則是一個語句。 因為這一點,lambda能夠出現在Python語法不允許def出現的地方,例如,在一個列表常量中或者函式呼叫的引數中。此外,作為一個表示式,lambda返回了一個值(一個新的函式),可以選擇性的賦值給一個變數名。相反,def語句總是得在頭部將一個新的函式賦值給一個變數名,而不是將這個函式作為結果返回。
  4. lambda是一個為編寫簡單的函式而設計的,而def用來處理更大的任務。lambda的主體是一個單個的表示式即冒號“:”後面只能有一個表示式,而def可以有多個即構成一個程式碼塊。lambda僅限於表示式,使得其功能通常要比def少得多:只能夠在lambda主體中將有限的邏輯封裝進去,像if或for或print等語句都不能在lambda中使用,但是可以在def中使用。
  5. lambda函式不能共享給別的程式呼叫,def可以。

lambda與def定義的普通函式相比,只是省去了函式名稱而已,而且這樣的匿名函式又不能在別的地方呼叫。但是lambda還是具有如下優點:

  1. 使用Python寫一些執行指令碼時,使用lambda可以省去定義函式的過程,讓程式碼更加精簡。
  2. 對於一些抽象的,不會別的地方再複用的函式,有時候給函式起個名字也是個難題,使用lambda不需要考慮命名的問題。
  3. 使用lambda在某些時候讓程式碼更容易理解。

與map/filter/reduce的聯合使用

使用lambda定義的匿名函式可與Python提供的map、filter、reduce等全域性函式結合使用,其示例如下所示:

>>> list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> map(lambda x: x * 2, list)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
>>> filter(lambda x: x % 3 == 0, list)
[3, 6, 9]
>>> reduce(lambda x, y: x + y, list)
55

使用場景

替換形式

雖然可以在Python程式中使用lambda以達到一定的簡潔程度,但是卻並不一定非要使用lambda。

在物件遍歷處理方面,Python語言提供的for..in..if語法非常強大,並且在易讀性上勝過了lambda,比如在上面的map例子可以修改為如下:

>>> [x * 2 for x in list]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

上面的filter例子可以修改為如下:

>>> [x for x in list if x % 3 == 0]
[3, 6, 9]

所以,什麼時候使用lambda,什麼時候不用,需要具體情況具體分析,只要表達的意圖清晰就好。一般情況下,如果for..in..if能做的,儘量不要使用lambda。

常見問題

引數問題

如果想建立一個函式陣列fs=[f_0, …, f_n],其中f_i(n)=i+n。於是定義了這麼一個lambda函式:

>>> fs = [(lambda n: i + n) for i in range(10)]
>>> fs[3](4)
13
>>> fs[4](4)
13
>>> fs[5](4)
13

顯然,這樣定義的lambda函式並不能正確實現預期的功能。問題其實出在變數i上,lambda中的i使用的是匿名函式外的全域性變數,即使用到的i的值都為9。可將程式碼修改為如下:

>>> fs = [(lambda n, i=i : i + n) for i in range(10)]
>>> fs[3](4)
7
>>> fs[4](4)
8

lambda的例子
lambda的使用情況及不適用情況