Python函數語言程式設計(map()、filter()和reduce())詳解

2020-07-16 10:05:01
所謂函數語言程式設計,是指程式碼中每一塊都是不可變的,都由純函數的形式組成。這裡的純函數,是指函數本身相互獨立、互不影響,對於相同的輸入,總會有相同的輸出。

除此之外,函數語言程式設計還具有一個特點,即允許把函數本身作為引數傳入另一個函數,還允許返回一個函數。

例如,想讓列表中的元素值都變為原來的兩倍,可以使用如下函數實現:
def multiply_2(list):
    for index in range(0, len(list)):
        list[index] *= 2
    return list
需要注意的是,這段程式碼不是一個純函數的形式,因為列表中元素的值被改變了,如果多次呼叫 multiply_2() 函數,那麼每次得到的結果都不一樣。

而要想讓 multiply_2() 成為一個純函數的形式,就得重新建立一個新的列表並返回,也就是寫成下面這種形式:
def multiply_2_pure(list):
    new_list = []
    for item in list:
        new_list.append(item * 2)
    return new_list

函數語言程式設計的優點,主要在於其純函數和不可變的特性使程式更加健壯,易於偵錯和測試;缺點主要在於限制多,難寫。

注意,純粹的函數語言程式設計語言(比如 Scala),其編寫的函數中是沒有變數的,因此可以保證,只要輸入是確定的,輸出就是確定的;而允許使用變數的程式設計語言,由於函數內部的變數狀態不確定,同樣的輸入,可能得到不同的輸出。

Python 允許使用變數,所以它並不是一門純函數語言程式設計語言。Python 僅對函數語言程式設計提供了部分支援,主要包括 map()、filter() 和 reduce() 這 3 個函數,它們通常都結合 lambda 匿名函數一起使用。接下來就對這 3 個函數的用法做逐一介紹。

Python map()函數

map() 函數的基本語法格式如下:

map(function, iterable)

其中,function 參數列示要傳入一個函數,其可以是內建函數、自定義函數或者 lambda 匿名函數;iterable 表示一個或多個可疊代物件,可以是列表、字串等。

map() 函數的功能是對可疊代物件中的每個元素,都呼叫指定的函數,並返回一個 map 物件。

注意,該函數返回的是一個 map 物件,不能直接輸出,可以通過 for 迴圈或者 list() 函數來顯示。

【例 1】還是對列表中的每個元素乘以 2。
listDemo = [1, 2, 3, 4, 5]
new_list = map(lambda x: x * 2, listDemo)
print(list(new_list))
執行結果為:

[2, 4, 6, 8, 10]


【例 2】map() 函數可傳入多個可疊代物件作為引數。
listDemo1 = [1, 2, 3, 4, 5]
listDemo2 = [3, 4, 5, 6, 7]
new_list = map(lambda x,y: x + y, listDemo1,listDemo2)
print(list(new_list))
執行結果為:

[4, 6, 8, 10, 12]

注意,由於 map() 函數是直接由用 C 語言寫的,執行時不需要通過 Python 直譯器間接呼叫,並且內部做了諸多優化,所以相比其他方法,此方法的執行效率最高。

Python filter()函數

filter()函數的基本語法格式如下:

filter(function, iterable)

此格式中,funcition 參數列示要傳入一個函數,iterable 表示一個可疊代物件。

filter() 函數的功能是對 iterable 中的每個元素,都使用 function 函數判斷,並返回 True 或者 False,最後將返回 True 的元素組成一個新的可遍歷的集合。

【例 3】返回一個列表中的所有偶數。
listDemo = [1, 2, 3, 4, 5]
new_list = filter(lambda x: x % 2 == 0, listDemo)
print(list(new_list))
執行結果為:

[2, 4]


【例 4】filter() 函數可以接受多個可疊代物件。
listDemo = [1, 2, 3, 4, 5]
new_list = map(lambda x,y: x-y>0,[3,5,6],[1,5,8] )
print(list(new_list))
執行結果為:

[True, False, False]

Python reduce()函數

reduce() 函數通常用來對一個集合做一些累積操作,其基本語法格式為:

reduce(function, iterable)

其中,function 規定必須是一個包含 2 個引數的函數;iterable 表示可疊代物件。

注意,由於 reduce() 函數在 Python 3.x 中已經被移除,放入了 functools 模組,因此在使用該函數之前,需先匯入 functools 模組。

【例 5】計算某個列表元素的乘積。
import functools
listDemo = [1, 2, 3, 4, 5]
product = functools.reduce(lambda x, y: x * y, listDemo)
print(product)
執行結果為:

120

總結

通常來說,當對集合中的元素進行一些操作時,如果操作非常簡單,比如相加、累積這種,那麼應該優先考慮使用 map()、filter()、reduce() 實現。另外,在資料量非常多的情況下(比如機器學習的應用),一般更傾向於函數語言程式設計的表示,因為效率更高。

當然,在資料量不多的情況下,使用 for 迴圈等方式也可以。不過,如果要對集合中的元素做一些比較複雜的操作,考慮到程式碼的可讀性,通常會使用 for 迴圈。