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具有如下區別:
- def定義的普通函式是有函式名稱的,而lambda定義的函式並沒有函式名稱,因此也被稱為匿名函式。
- lambda會返回一個函式物件,但不會為這個物件賦予一個識別符號,而def則會把函式物件賦值給一個變數即函式名。
- lambda只是一個表示式,而def則是一個語句。 因為這一點,lambda能夠出現在Python語法不允許def出現的地方,例如,在一個列表常量中或者函式呼叫的引數中。此外,作為一個表示式,lambda返回了一個值(一個新的函式),可以選擇性的賦值給一個變數名。相反,def語句總是得在頭部將一個新的函式賦值給一個變數名,而不是將這個函式作為結果返回。
- lambda是一個為編寫簡單的函式而設計的,而def用來處理更大的任務。lambda的主體是一個單個的表示式即冒號“:”後面只能有一個表示式,而def可以有多個即構成一個程式碼塊。lambda僅限於表示式,使得其功能通常要比def少得多:只能夠在lambda主體中將有限的邏輯封裝進去,像if或for或print等語句都不能在lambda中使用,但是可以在def中使用。
- lambda函式不能共享給別的程式呼叫,def可以。
lambda與def定義的普通函式相比,只是省去了函式名稱而已,而且這樣的匿名函式又不能在別的地方呼叫。但是lambda還是具有如下優點:
- 使用Python寫一些執行指令碼時,使用lambda可以省去定義函式的過程,讓程式碼更加精簡。
- 對於一些抽象的,不會別的地方再複用的函式,有時候給函式起個名字也是個難題,使用lambda不需要考慮命名的問題。
- 使用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的使用情況及不適用情況