函數(shù)式編程 (Functional Programming) 或者函數(shù)程序設(shè)計(jì),又稱泛函編程,是一種編程范型,它將計(jì)算機(jī)運(yùn)算視為數(shù)學(xué)上的函數(shù)計(jì)算,并且避免使用程序狀態(tài)以及易變對象。在Python中,函數(shù)式編程主要由幾個函數(shù)的使用構(gòu)成:partial( ), lambda( ), map( ), reduce( ), filter( )。
partial( )
在傳遞函數(shù)的時候,有時我們可能想部分地應(yīng)用函數(shù)來創(chuàng)建新函數(shù)。這種情況下,一個巧妙的方法就是利用 functools.partial 創(chuàng)建。
def exp(base, power):
return base ** power # 這是一個二元函數(shù)
如果我們想用上述的二元函數(shù)創(chuàng)建一個新的函數(shù) two_to_the: 它的輸入是一個冪次( power),輸出的是exp(2, power) 的結(jié)果。
def two_to_the(power):
return exp(2,power)
print two_to_the(3) # 8
一種另辟蹊徑的方法是使用 functools.partial:
from functools import partial
two_to_the = partial(exp, 2)
print two_to_the(3) # 8
當(dāng)然,也可以指定參數(shù)的名字:
square_of = partial(exp, power=2)
print square_of(3) # 9
lambda( )
lambda( )主要用于定義“行內(nèi)函數(shù)”,有點(diǎn)像Matlab的“匿名函數(shù)”,具體的操作如下:
f = lambda x : x + 2 # 定義函數(shù) f(x)=x+2
g = lambda x, y : x + y # 定義函數(shù) g(x, y)=x+y
map( )
map( ) 函數(shù)用于逐一遍歷。例如我們有一個list a = [1, 2, 3, 4], 要給 a 中的每一個元素加2得到一個新的list,有兩種方式:
b = [i+2 for i in a] # list comprehension
b = map(lambda x : x+2, a) # map( )
當(dāng)然,如果對多個列表操作,可以對帶有多個參數(shù)的函數(shù)使用 map( ) :
products = map(lambda x, y : x * y, [1, 2], [3, 4]) # [1*3, 2*4] = [3, 8]
有了列表解析 (list comprehension) , 為什么還用 map( ) 函數(shù)呢?其實(shí),列表解析雖然代碼簡單,但本質(zhì)上還是 for 循環(huán)命令,而 Python 的 for 循環(huán)命令效率不高,而 map( ) 函數(shù)實(shí)現(xiàn)了相同的功能,并且效率更高,原則上,它的循環(huán)命令速度相當(dāng)于 C 語言。
reduce( )
和 map( ) 函數(shù)類似,但 map( ) 函數(shù)用于逐一遍歷,而 reduce( ) 函數(shù)用于遞歸計(jì)算。
multiply = reduce(lambda x, y : x * y, [1, 2, 3, 4]) # 1 * 2 * 3 * 4 = 24
reduce( ) 結(jié)合了列表的兩個元素,它們的結(jié)果又結(jié)合列表的第3個元素,這個結(jié)果之后又結(jié)合了第4個元素,依次下去,直到得到一個單獨(dú)的結(jié)果。
def multiply(x, y):
return x * y
list_product = partial(reduce, multiply) # 將函數(shù) multiply 作為參數(shù)傳給 reduce
x_product = list_product([1, 2, 3, 4])
上述的過程,同樣能夠?qū)崿F(xiàn)相應(yīng)的功能。
filter( )
顧名思義, filter( ) 是一個過濾器,用來篩選 list 中符合條件的元素,例如:
b = filter(lambda x : x > 5 and x < 8, range(10)) # [6, 7]
上述的 filter( ) 用列表解析可以寫作:
b = [i for i in range(10) if i > 5 and i < 8]
很明顯,filter( ) 做了列表解析中 if 的工作。
注:需要注意的是,列表解析并不比上述函數(shù)復(fù)雜,但我們使用函數(shù) partial( ), lambda( ), map( ), reduce( ), filter( ), 它們在兼顧簡潔和效率的同時也為列表解析提供了函數(shù)式替代方案。
Stay hungry, Stay foolish. -- Steve Jobs