理解Python中的Lambda函式

劉志軍發表於2019-03-01

Python 中定義函式有兩種方法,一種是用常規方式 def 定義,函式要指定名字,第二種是用 lambda 定義,不需要指定名字,稱為 Lambda 函式。

Lambda 函式又稱匿名函式,匿名函式就是沒有名字的函式,函式沒有名字也行?當然可以啦。有些函式如果只是臨時一用,而且它的業務邏輯也很簡單時,就沒必要非給它取個名字不可。

好比電影裡面的群眾演員,往往他們的戲份很少,最多是襯托主演,跑跑龍套,他們需要名字嗎?不需要,因為他們僅僅只是臨時出鏡,下次可能就用不著了,所以犯不著費心思給他們每個人編個號取個名字,畢竟取個優雅的名字是很費勁的事情。

先來看個簡單 lambda 函式

>>> lambda x, y : x+y
<function <lambda> at 0x102bc1c80>複製程式碼

x 和 y 是函式的兩個引數,冒號後面的表示式是函式的返回值,你能一眼看出這個函式就是是在求兩個變數的和,但作為一個函式,沒有名字如何使用呢?這裡我們暫且給這個匿名函式繫結一個名字,這樣使得我們呼叫匿名函式成為可能

>>> add = lambda x, y : x+y
>>> add
<function <lambda> at 0x102bc2140>
>>> add(1,2)
3複製程式碼

它等同於常規函式

>>> def add2(x, y):
...     return x+y
...
>>> add2
<function add2 at 0x102bc1c80>
>>> add2(1,2)
3複製程式碼

如果定義匿名函式,還要給它繫結一個名字的話,有點畫蛇添足,通常是直接使用 lambda 函式。那麼 lamdba 函式的正確使用場景在哪呢?

1、函數語言程式設計

儘管 Python 算不上是一門純函數語言程式設計語言,但它本身提供了很多函數語言程式設計的特性,像 map、reduce、filter、sorted 這些函式都支援函式作為引數,lambda 函式就可以應用在函數語言程式設計中。

請看題:一個整數列表,要求按照列表中元素的絕對值大小升序排列,你會怎麼做?思考一分鐘往下看

>>> list1 = [3,5,-4,-1,0,-2,-6]
>>> sorted(list1, key=lambda x: abs(x))
[0, -1, -2, 3, -4, 5, -6]複製程式碼

排序函式 sorted 支援接收一個函式作為引數,該引數作為 sorted 的排序依據,這裡按照列表元素的絕對值進行排序,當然,我也可以用普通函式來實現:

>>> def foo(x):
...     return abs(x)
...
>>> sorted(list1, key=foo)
[0, -1, -2, 3, -4, 5, -6]複製程式碼

只不過是這種方式程式碼看起來不夠 Pythonic 而已。

2、閉包

閉包本身是一個晦澀難懂的概念,它可以專門單獨用一篇文章來介紹,不過在這裡我們可以簡單粗暴地理解為閉包就是一個定義在函式內部的函式,閉包使得變數即使脫離了該函式的作用域範圍也依然能被訪問到。

來看一個用 lambda 函式作為閉包的例子。

>>> def my_add(n):
...     return lambda x:x+n
...
>>> add_3 = my_add(3)
>>> add_3(7)
10複製程式碼

這裡的 lambda 函式就是一個閉包,在全域性作用域範圍中,add_3(7) 可以正常執行且返回值為10,之所以返回10是因為在 my_add 區域性作用域中,變數 n 的值在閉包的作用使得它在全域性作用域也可以被訪問到。

換成常規函式也可以實現閉包,只不過是這種方式稍顯囉嗦。

>>> def my_add(n):
...     def wrapper(x):
...         return x+n
...     return wrapper
...
>>> add_5 = my_add(5)
>>> add_5(2)
7複製程式碼

那麼是不是任何情況 lambda 函式都要比常規函式更清晰明瞭呢?看這個例子:

f = lambda x: [[y for j, y in enumerate(set(x)) if (i >> j) & 1] for i in range(2**len(set(x)))]複製程式碼

這是一個返回某個集合的所有子集的 lambda 函式,你看明白了嗎?我是很難一眼看出來

zen of python 中有這樣一句話是 Explicit is better than implicit(明瞭勝於晦澀)。記住,如果用 lambda 函式不能使你的程式碼變得更清晰時,這時你就要考慮使用常規的方式來定義函式。


5月4日晚上8點,我在CSDN直播《爬蟲入門與實踐》,有興趣的可以去看看,需要優惠的可以在公眾號留言,暗號「福利」。

同步發表:foofish.net/lambda.html
公眾號 Python之禪 (id:VTtalk),分享 Python 等技術乾貨

理解Python中的Lambda函式

相關文章