深入詳解python高級特性——函數(shù)柯里化(Currying)與反柯里化

前言:本章的內(nèi)容本來很簡單,但是涉及到的理論部分相對較多,想要徹底弄懂前因后果需要具備以下幾個知識點,
(1)python的高階函數(shù)
(2)python的裝飾器本質(zhì)
(3)Python的functools模塊里面的偏函數(shù)的本質(zhì)
這三塊類容我在之前的文章中已經(jīng)有詳細(xì)說明了,不再贅述,可以參考下面的連接中的文章:
博客專欄分類,關(guān)于Python的各種高級特性都有說明
關(guān)于functools模塊以及偏函數(shù)的詳細(xì)理解
一、什么是函數(shù)柯里化(Currying)
函數(shù)柯里化是解釋型語言常見的一種特性,常見的語言比如python、javascript都支持函數(shù)柯里化
有兩種理解,當(dāng)然這兩種理解的本質(zhì)實際上是表達(dá)同一層含義,如下:
定義一:
柯里化:一個函數(shù)中有個多個參數(shù),想固定其中某個或者幾個參數(shù)的值,而只接受另外幾個還未固定的參數(shù),這樣函數(shù)演變成新的函數(shù)。
定義二:
函數(shù)柯里化(currying)又稱部分求值。一個 currying 的函數(shù)首先會接受一些參數(shù),接受了這些參數(shù)之后,該函數(shù)并不會立即求值,而是繼續(xù)返回另外一個函數(shù),剛才傳入的參數(shù)在函數(shù)形成的閉包中被保存起來。待到函數(shù)被真正需要求值的時候,之前傳入的所有參數(shù)都會被一次性用于求值。
定義三:
一些函數(shù)式語言的工作原理是將多參數(shù)函數(shù)語法轉(zhuǎn)化為單參數(shù)函數(shù)集合,這一過程稱為柯里化,它是以邏輯學(xué)家Haskell Curry的名字命名的。Haskell Curry從早期概念中發(fā)展出了該理論。其形式相當(dāng)于將z = f(x, y)轉(zhuǎn)換成z = f(x)(y)的形式,原函數(shù)由兩個參數(shù),現(xiàn)在變?yōu)閮蓚€接受單參數(shù)的函數(shù),在函數(shù)式編程語言中,這種特性很常見。
柯里化是一種將多參數(shù)函數(shù)轉(zhuǎn)化為單參數(shù)高階函數(shù)的技術(shù)。例如函數(shù)?f(x,y) -> z,對于給定的兩個參數(shù) x 和 y ,該函數(shù)會返回?z?值作為結(jié)果??梢詫?f(x,y) 柯里化為兩個函數(shù):f(x)(y) -> z。
即?
f(x1,x2,x3,x4) ——> f(x1)(x2)(x3)(x4)
?
1.1 從一個例子來說起——按照定義二來實現(xiàn)
現(xiàn)在有一個函數(shù)add1,作用是實現(xiàn)三個數(shù)字相加,現(xiàn)在我們想要固定其中的第二個參數(shù)不變,調(diào)用的時候只指定第一個、第三個參數(shù),艱難單的實現(xiàn)如下:
def?add1(a,?b,?c):
????return?a?+?b?+?c
def?add2(a,?b):
????return?add1(a,?666,?b)
result?=?add2(12,13)
print(result)
不錯,這就是函數(shù)柯里化的簡單實現(xiàn),因為在python中一切皆對象,函數(shù)也是一種對象,所以實現(xiàn)起來很簡單靈活,
1.2 python函數(shù)柯里化的不同實現(xiàn)方法——基于定義一、定義二
(1)通過functools提供的偏函數(shù)來實現(xiàn)
from?functools?import?partial
def?add1(a,?b,?c):
????return?a?+?b?+?c
add2?=?partial(add1,?b=666)
#?使用?partial?來實現(xiàn)偏函數(shù)時,要指定參數(shù)名
result?=?add2(a?=?12,?c?=?13)
print(result)
(2)定義兩個函數(shù),用函數(shù)2來包裝函數(shù)1
如上面所示,用add2來包裝add1,這里不再贅述
(3)使用lambda表達(dá)式來完成
既然可以用一個函數(shù)包裝另一個函數(shù),自然可以使用lambda表達(dá)式來實現(xiàn),如下所示:
def?add1(a,?b,?c):
????return?a?+?b?+?c
#?使用lambda表達(dá)式柯里化,固定第二個參數(shù)b=666
add2?=?lambda?x,y:add_number(x,666,y)
result?=?add2(12,?13)
print(result)
(4)使用python的裝飾器來實現(xiàn)
這就是最開始為什么強(qiáng)調(diào)深入理解python高級特性“裝飾器”是非常有幫助的,關(guān)于python裝飾器的系列文章,可以參考我前面的博客。代碼如下:
def?add(a,?b,?c):
????return?a?+?b?+?c
def?currying_add(func):
????def?wrapper(a,?c,?b=666):
????????return?func(a,?b,?c)
????return?wrapper
result?=?currying_add(add)(1,2)
print(result)??#?669
如果是使用裝飾器符號@該怎么實現(xiàn)呢?如下:
def?currying_add(func):
????def?wrapper(a,?c,?b=666):
????????return?func(a,?b,?c)
????return?wrapper
#?使用裝飾器符號來定義函數(shù)add,add?=?currying_add(add)
@currying_add
def?add(a,?b,?c):
????return?a?+?b?+?c
result?=?add(1,2)
print(result)??#?669
(5)通過pymond模塊;來實現(xiàn)currying
from pymonad import curry?
1.2 python函數(shù)柯里化的不同實現(xiàn)方法——基于定義三
這里是實現(xiàn)以下功能,一個函數(shù)有多個參數(shù),將其拆分成幾個函數(shù),每一個函數(shù)只具有其中的部分參數(shù),實現(xiàn)函數(shù)參數(shù)的拆分。
如下代碼:
def?add(x,?y):
????return?x?+?y
#?柯里化
def?currying_add(x):
????def?inc(y):
????????return?x?+?y
????return?inc??#?返回函數(shù)
result?=?currying_add(2)(3)
print(result)???#?5
柯里化的通俗總結(jié):
不管是基于第一種、第二種定義,他更加側(cè)重于將一個函數(shù)的多個參數(shù)中的其中幾個先固定,這樣減少參數(shù)的數(shù)量
還是基于第三中定義,它更加側(cè)重于將函數(shù)的多個參數(shù)拆分成少量幾個參數(shù)的組成,其實它們的本質(zhì)都是一樣,它們的實現(xiàn)核心思想也是一樣的,真正核心的地方就在于“高階函數(shù)”。
注意:柯里化的第一種定義、第二種定義看似是和函數(shù)定義默認(rèn)值相似,但是默認(rèn)值只能定義單個固定值,而柯里化能泛化出多個不同固定值但是相同計算規(guī)則的函數(shù)。
?
二、什么是函數(shù)反柯里化?
前面說的函數(shù)柯里化是實現(xiàn)這樣的功能,即:
f(x1,x2,x3,x4) ——> f(x1)(x2)(x3)(x4)
那么實際上,函數(shù)的反柯里化就是恰好反過來的過程,即實現(xiàn)
f(x1)(x2)(x3)(x4)——>f(x1,x2,x3,x4)
含義的確是比較好理解,但是Python中比較少的用到,因為我們更多的使用函數(shù)柯里化操作,我們很少見到python中調(diào)用函數(shù)通過下面這樣的方式調(diào)用吧,即:
f(x1)(x2)(x3)(x4)
所以函數(shù)反柯里化實際上一般都是和函數(shù)柯里化來結(jié)合使用,我們參見下面的例子:
#?定義加法函數(shù)
def?add(x,?y):
????return?x?+?y
#?柯里化
def?currying_add(x):
????def?inc(y):
????????return?x?+?y
????return?inc??#?返回函數(shù)
#?因為currying_add()是一個柯里化函數(shù),現(xiàn)在我針對他定義一個反柯里化函數(shù),如下:
def?anti_currying_add(x,y):
????return?currying_add(x)(y)
result?=?anti_currying_add(2,3)??#?調(diào)用反柯里化函數(shù)
print(result)???#?5
就是這么簡單,其實這一個特性最重要的理解就在于“高階函數(shù)”。

●?完結(jié)撒花!2020最新版《神經(jīng)網(wǎng)絡(luò)和深度學(xué)習(xí)》中文版PDF開放下載?

?機(jī)器學(xué)習(xí)與python集中營
視覺算法、機(jī)器學(xué)習(xí)、深度學(xué)習(xí)、python開發(fā)。百篇原創(chuàng)文章,用最通俗的言語闡述晦澀的理論,讓我們來一次美好的邂逅吧!
