Python 擴充之特殊函式(lambda 函式,map 函式,filter 函式,reduce 函式)

Rocky0429發表於2018-12-20

寫在之前

今天給大家介紹幾個比較特殊的函式,他們具有函數語言程式設計的特點,有人將它們視為 Python 可進行 「函數語言程式設計」 的見證,至於什麼是函數語言程式設計,不是本篇文章的重點,感興趣的可以去了解一下。老讀者可能都知道,我非常推崇 Python 的簡潔優雅,而今天的這幾個函式,有了它們,最大的好處就是可以讓程式更簡潔,當然,沒有它們程式也可以用其它方式實現。

lambda 函式

lambda 是一個可以只用一行就能解決問題的函式,讓我們先看下面的例子:

>>> def add(x):
...     x += 1
...     return x
...
>>> numbers = range(5)
>>> list(numbers)
[0, 1, 2, 3, 4]
>>> new_numbers = []
>>> for i in numbers:
...     new_numbers.append(add(i))
...
>>> new_numbers
[1, 2, 3, 4, 5]
複製程式碼

在上面的這個例子中,函式 add() 充當了一箇中間角色,當然上面的例子也可以如下實現:

>>> new_numbers = [i+1 for i in numbers]
>>> new_numbers
[1, 2, 3, 4, 5]
複製程式碼

首先我要說,上面的列表解析式其實是很好用的,但是我偏偏要用 lambda 這個函式代替 add(x)

>>> lamb = lambda x: x+1
>>> new_numbers = []
>>> for i in numbers:
...     new_numbers.append(lamb(i))
...
>>> new_numbers
[1, 2, 3, 4, 5]
複製程式碼

在這裡的 lamb 就相當於 add(x) ,lamb = lambda x : x+1 就相當於 add(x) 裡的程式碼塊。下面再寫幾個應用 lambda 的小例子:

>>> lamb = lambda x,y : x + y
>>> lamb(1,2)
3
>>> lamb1 = lambda x : x ** 2
>>> lamb1(5)
25
複製程式碼

由上面的例子我們可以總結一下 lambda 函式的具體使用方法:lambda 後面直接跟變數,變臉後面是冒號,冒號後面是表示式,表示式的計算結果就是本函式的返回值。

在這裡有一點需要提醒的是,雖然 lambda 函式可以接收任意多的引數並且返回單個表示式的值,但是 lambda 函式不能包含命令且包含的表示式不能超過一個。如果你需要更多複雜的東西,你應該去定義一個函式。

lambda 作為一個只有一行的函式,在你具體的程式設計實踐中可以選擇使用,雖然在效能上沒什麼提升,但是看著舒服呀。

map 函式

我們在上面講 lambda 的時候用的例子,其實 map 也可以實現,請看下面的操作:

>>> numbers = [0,1,2,3,4]
>>> map(add,numbers)
[1, 2, 3, 4, 5]
>>> map(lambda x: x + 1,numbers)
[1, 2, 3, 4, 5]
複製程式碼

map 是 Python 的一個內建函式,它的基本格式是:map(func, seq)

func 是一個函式物件,seq 是一個序列物件,在執行的時候,seq 中的每個元素按照從左到右的順序依次被取出來,塞到 func 函式裡面,並將 func 的返回值依次存到一個列表裡。

對於 map 要主要理解以下幾個點就好了:

1.對可迭代的物件中的每一個元素,依次使用 fun 的方法(其實本質上就是一個 for 迴圈)。

2.將所有的結果返回一個 map 物件,這個物件是個迭代器。

我們接下來做一個簡單的小題目:將兩個列表中的對應項加起來,把結果返回在一個列表裡,我們用 map 來做,如果你做完了,請往下看:

>>> list1 = [1,2,3,4]
>>> list2 = [5,6,7,8]
>>> list(map(lambda x,y: x + y,list1,list2))
[6, 8, 10, 12]
複製程式碼

你看上面,是不是很簡單?其實這個還看不出 map 的方便來,因為用 for 同樣也不麻煩,要是你有這樣的想法的話,那麼請看下面:

>>> list1 = [1,2,3,4]
>>> list2 = [5,6,7,8]
>>> list3 = [9,10,11,12]
>>> list(map(lambda x,y,z : x + y + z,list1,list2,list3))
[15, 18, 21, 24]
複製程式碼

你看三個呢?是不是用 for 的話就稍顯麻煩了?那麼我們在想如果是 四個,五個乃至更多呢?這就顯示出 map 的簡潔優雅了,並且 map 還不和 lambda 一樣對效能沒有什麼提高,map 在效能上的優勢也是槓槓的。

filter 函式

filter 翻譯過來的意思是 “過濾器”,在 Python 中,它也確實是起到的是過濾器的作用。這個解釋起來略微麻煩,還是直接上程式碼的好,在程式碼中體會用法是我在所有的文章裡一直在體現的:

>>> numbers = range(-4,4)
>>> list(filter(lambda x: x > 0,numbers))
[1, 2, 3]
複製程式碼

上面的例子其實和下面的程式碼是等價的:

>>> [x for x in numbers if x > 0]
[1, 2, 3]
複製程式碼

然後我們再來寫一個例子體會一下:

>>> list(filter(lambda x: x != 'o','Rocky0429'))
['R', 'c', 'k', 'y', '0', '4', '2', '9']
複製程式碼

reduce 函式

我在之前的文章中很多次都說過,我的程式碼都是用 Python3 版本的。在 Python3 中,reduce 函式被放到 functools 模組裡,在 Python2 中還是在全域性名稱空間。

同樣我先用一個例子來跑一下,我們來看看怎麼用:

>>> reduce(lambda x,y: x+y,[1,2,3,4])
10
複製程式碼

reduce 函式的第一個引數是一個函式,第二個引數是序列型別的物件,將函式按照從左到右的順序作用在序列上。如果你還不理解的話,我們下面可以對比一下它和 map 的區別:

>>> list1 = [1,2,3,4]
>>> list2 = [5,6,7,8]
>>> list(map(lambda x,y: x + y,list1,list2))
[6, 8, 10, 12]
複製程式碼

對比上面的兩個例子,就知道兩者的區別,map 相當於是上下運算的,而 reduce 是從左到右逐個元素進行運算。

寫在之後

至此,我在上面介紹了四個函式,這些函式不僅使得程式碼更加的簡單,而且在 Python3 中也優化了它們的效能。所以如果你喜歡的話,儘可以放心大膽的使用。

更多內容,歡迎關注公眾號「Python空間」,期待和你的交流。

在這裡插入圖片描述

相關文章