??在第一部分簡單介紹了python的函數(shù)式編程基本方法后,從這部分開始將開始更深入的學(xué)習(xí)toolz的使用方法。話不多說,下面開始上示例代碼。
??將上一部分的函數(shù)拿來繼續(xù)用
def add(x, y):
return x + y
def mul(x, y):
return x * y
def lesser(x, y):
if x < y:
return x
else:
return y
def greater(x, y):
if x > y:
return x
else:
return y
??首先是accumulate的用法,功能類似于numpy的累加,不過操作(加、乘或其他計(jì)算)具體由傳入的第一個(gè)參數(shù)來決定;又可以看出和reduce相近,只不過reduce只返回最后的結(jié)果
import numpy as np
X[X>=10].cumsum()
# >>>array([ 10, 21, 33, 46, 60, 75, 91, 108, 126, 145], dtype=int32)
data = range(10, 20)
list(accumulate(add, data))
# >>>[10, 21, 33, 46, 60, 75, 91, 108, 126, 145]
from functools import reduce
reduce(add,data)
# >>>145
??繼續(xù)來看map、reduce、accumulate的更靈活的一些用法,
data1 = [1, 2, 3, 4, 5]
data2 = [10, 20, 30, 40, 50]
list(map(add, data1, data2))
# >>>[11, 22, 33, 44, 55]
reduce(lesser, [5, 3, 2, 7, 3], 999999999) # 注意第三個(gè)參數(shù)為初值
# >>> 2
reduce(lesser, [5, 3, 2, 7, 3], 1)
# >>> 1
list(accumulate(lesser, [5, 3, 2, 7, 3]))
# >>> [5, 3, 2, 2, 2]
??可以看出map、reduce、accumulate的第一個(gè)參數(shù)需要傳入一個(gè)兩個(gè)參數(shù)的函數(shù)(類似于雙目運(yùn)算符)。
??到現(xiàn)在為止,熱身活動(dòng)已經(jīng)結(jié)束了,開始介紹下面重要的一個(gè)概念,函數(shù)的柯里化(Currying,中文翻譯還是有些怪,看英文有可能突然想到投3分的庫里啊)。首先介紹python中的幾種處理高階函數(shù)(higher order function)的方式,高階函數(shù)可以簡單理解為函數(shù)的函數(shù),即函數(shù)可以當(dāng)做變量傳來傳去,從而達(dá)到更靈活的用法。
#方式1 普通函數(shù)
def cumsum(data):
return accumulate(add, data)
#方式2 匿名函數(shù)
cumsum = lambda data: accumulate(add, data)
#方式3 偏函數(shù)
from functools import partial
cumsum = partial(accumulate, add)
#三種方式都是下面一個(gè)結(jié)果
list(cumsum(data))
# >>>[10, 21, 33, 46, 60, 75, 91, 108, 126, 145]
??我們用高階函數(shù)的方式實(shí)現(xiàn)了一個(gè)輸出每步累加值的函數(shù)cumsum,除了普通函數(shù)的方式外,另外兩種方式個(gè)人感覺都還算pythonic,選哪種看個(gè)人喜好了。
??同樣的功能,更函數(shù)式的方式,下面輪到神射手curry出場(chǎng)了!
from toolz import curry
mul_cur = curry(mul)
mul_cur(2) # 傳入?yún)?shù)后返回一個(gè)函數(shù),然后就剩下一個(gè)參數(shù)可傳了
# >>> <function mul at 0x00000000072A1EA0>
mul_cur(2)(3)
# >>> mul_cur(2)(3)
# 方式4 currying的方式
accumulate = curry(accumulate)
cumsum = accumulate(add)
??用斐波那契函數(shù)的例子來說明一下稍微復(fù)雜一點(diǎn)的情況,生成斐波那契數(shù)列的前10個(gè)數(shù)字,但是又不想(或者不能)改變fib函數(shù)的前提下(雖然我知道這樣執(zhí)行效率低),通過curry來得到了一個(gè)新的函數(shù),相比于直接用列表展開或者每次都用map去做的話,肯定是更加方便快捷,并且通過新的函數(shù)名提高了程序的可讀性。
def fib(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return b
fib(9)
# >>> 55
map = curry(map)
fibMany = map(fib)
list(fibMany(range(10)))
# >>> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
??最后,告訴大家其實(shí)沒必要每次都用curry去“包裹”一次map,toolz里面做好準(zhǔn)備工作,提供了相關(guān)的柯里化好的函數(shù)。
from toolz.curried import map, accumulate, reduce, filter
# 函數(shù)很多就不一一列舉了, 這些都等價(jià)于下面手動(dòng)柯里化
from toolz import map, curry
map = curry(map)
??未完待續(xù) ...