Python 提供 3 種內(nèi)建函數(shù)和 lambda 表達(dá)式等來(lái)支持函數(shù)式編程。
匿名函數(shù)
Python 允許用 lambda 關(guān)鍵字創(chuàng)造匿名函數(shù)耙替。匿名顧名思義就是沒有名字,即不需要以標(biāo)準(zhǔn)的方式來(lái)聲明,比如說(shuō),使用 def 加函數(shù)名來(lái)聲明沼沈。一個(gè)完整的 lambda “語(yǔ)句”代表了一個(gè)表達(dá)式,這個(gè)表達(dá)式的定義體必須和聲明放在同一行币厕。語(yǔ)法如下:
lambda [arg1[, arg2, ... argN]]: expression
參數(shù)是可選的列另,如果使用參數(shù)的話,參數(shù)通常也會(huì)出現(xiàn)在表達(dá)式中旦装。
注意:lambda 表達(dá)式返回可調(diào)用的函數(shù)對(duì)象页衙。其實(shí) lambda 表達(dá)式本身就是一個(gè)函數(shù),這個(gè)函數(shù)定義了輸入(冒號(hào)左邊)和輸出(冒號(hào)右邊),只不過(guò)這個(gè)函數(shù)沒有名字店乐,但是我們可以把它賦給一個(gè)變量艰躺。
比如簡(jiǎn)單的加法函數(shù)。一般我們是這么寫的:
def add(x, y):
return x+y
lambda 表達(dá)式這么寫:
lambda x, y : x + y
我們可以把 lambda x, y : x + y 賦值給 f 响巢,然后給 f 傳參數(shù):
>>> f = lambda x, y : x + y
>>> f
at 0x10377f320>
>>> f(-10,8)
-2
>>> f(12, 100)
112
>>> f(-33, -22)
-55
可以看到描滔,f 確實(shí)是個(gè)函數(shù),可以接收兩個(gè)參數(shù)踪古,并返回這兩個(gè)參數(shù)的和,等價(jià)于上面的 add 函數(shù)券腔。
使用場(chǎng)景
1伏穆、函數(shù)式編程
2、閉包
簡(jiǎn)單粗暴地理解為閉包就是一個(gè)定義在函數(shù)內(nèi)部的函數(shù)纷纫,閉包使得變量即使脫離了該函數(shù)的作用域范圍也依然能被訪問到枕扫。
高階函數(shù)
高階函數(shù)英文叫 Higher-order function 。一般函數(shù)的輸入?yún)?shù)和返回值都只能是變量或常量辱魁,如果某個(gè)函數(shù)可以接收函數(shù)作為其輸入?yún)?shù)烟瞧,或者其返回值中包含函數(shù),那么該函數(shù)就是高階函數(shù)染簇。
Python 中有三個(gè)內(nèi)建的用來(lái)支持函數(shù)式編程的高階函數(shù)参滴,分別是 filter(),map() 和 reduce()锻弓。
filter()
filter(function, sequence) 返回一個(gè) sequence (序列)砾赔,返回的序列中包括了輸入序列中所有調(diào)用 function(item) 后返回值為 true 的元素。
舉個(gè)栗子:
>>> def f(x): return x % 3 == 0 or x % 5 == 0
...
>>> filter(f, range(2, 25))
[3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24]
因?yàn)?filter() 的輸入?yún)?shù)中包含函數(shù) f() 青灼,所以 filter() 是高階函數(shù)暴心。上面的例子中返回 2~24 中能被 3 或 5 整除的數(shù)組成的列表。
當(dāng)然杂拨,也可以使用匿名函數(shù) lambda 表達(dá)式實(shí)現(xiàn):
>>> filter(lambda x : x % 3 == 0 or x % 5 == 0, range(2, 25))
[3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24]
或者使用列表生成式:
>>> [x for x in range(2, 25) if x % 3 == 0 or x % 5 == 0]
[3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24]
map()
map() 與 filter() 相似专普,因?yàn)樗材芡ㄟ^(guò)函數(shù)來(lái)處理序列。map()將函數(shù)調(diào)用“映射”到序列的每個(gè)元素上弹沽,并返回一個(gè)含有所有返回值的列表檀夹。
舉個(gè)栗子:
>>> def cube(x): return x**3
...
>>> map(cube, range(1,11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
上面的例子中,將 1~10 里的每個(gè)數(shù)分別調(diào)用 cube() 贷币,并將返回值(x 的 3 次方)放入列表中击胜。
lambda 表達(dá)式:
>>> map(lambda x : x**3, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
列表生成式:
>>> [x**3 for x in range(1, 11)]
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
注意:map() 也可以處理多個(gè)序列。
>>> map(lambda x, y: x + y, [1, 3, 5], [2, 4, 6])
[3, 7, 11]
>>> map(lambda x, y: (x+y, x-y), [1, 3, 5], [2, 4, 6])
[(3, -1), (7, -1), (11, -1)]
>>> map(None, [1, 3, 5], [2, 4, 6])
[(1, 2), (3, 4), (5, 6)]
reduce()
reduce(function, sequence) 返回一個(gè)單值役纹,它是這樣構(gòu)造的:首先以序列的前兩個(gè)元素調(diào)用函數(shù) function偶摔,再以返回值和第三個(gè)參數(shù)調(diào)用,依次執(zhí)行下去促脉。
例如辰斋,以下程序計(jì)算 0 到 5 的整數(shù)之和:
>>> def add(x, y): return x+y
...
>>> reduce(add, range(0, 5))
10
實(shí)際上 reduce() 執(zhí)行了如下的運(yùn)算:
((((0+1)+2)+3)+4) ==> 10
lambda 表達(dá)式:
reduce(lambda x, y : x + y, range(0, 5))
偏函數(shù)
偏函數(shù)解決這樣的問題:如果我們有函數(shù)是多個(gè)參數(shù)的策州,我們希望能固定其中某幾個(gè)參數(shù)的值(類似于默認(rèn)值)。
舉個(gè)栗子:
int() 函數(shù)可以把字符串轉(zhuǎn)換為整數(shù)宫仗,當(dāng)僅傳入字符串時(shí)够挂,int() 函數(shù)默認(rèn)按十進(jìn)制轉(zhuǎn)換:
>>> int('11111')
11111
但 int() 函數(shù)還提供額外的 base 參數(shù)(默認(rèn)值為10) 。如果傳入 base 參數(shù)藕夫,就可以做 N 進(jìn)制的轉(zhuǎn)換:
>>> int('11111',8)
4681
>>> int('11111',base=16)
69905
假設(shè)要轉(zhuǎn)換大量的二進(jìn)制字符串孽糖,每次都傳入 int(x, base=2) 非常麻煩,于是毅贮,我們想到办悟,可以定義一個(gè) int2() 的函數(shù),默認(rèn)把 base=2 傳進(jìn)去:
def int2(x, base=2):
return int(x, base)
這樣滩褥,我們就可以方便地轉(zhuǎn)換二進(jìn)制了:
>>> int2('1000000')
64
>>> int2('1010101')
85
functools.partial 就是幫助我們創(chuàng)建一個(gè)偏函數(shù)的病蛉,不需要我們自己定義 int2() ,可以直接使用下面的代碼創(chuàng)建一個(gè)新的函數(shù) int2 :
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('11111')
31
>>> int2('10000')
16
總結(jié)一下瑰煎,functools.partial 的作用就是铺然,把一個(gè)函數(shù)的某些參數(shù)給固定住(也就是設(shè)置默認(rèn)值)酒甸,返回一個(gè)新的函數(shù)魄健,調(diào)用這個(gè)新函數(shù)會(huì)更簡(jiǎn)單。
需要注意的是烘挫,上面的新的 int2 函數(shù)诀艰,僅僅是把 base 參數(shù)重新設(shè)定默認(rèn)值為 2 ,但也可以在函數(shù)調(diào)用時(shí)傳入其他值:
>>> int2('11111',base=10)
11111
>>> int2('11111',base=8)
4681