把函數(shù)作為參數(shù)傳入担败,這樣的函數(shù)稱為高階函數(shù)讯壶,函數(shù)式編程就是指這種高度抽象的編程范式
map/reduce
我們先看map雪情。map()函數(shù)接收兩個(gè)參數(shù),一個(gè)是函數(shù)鸭巴,一個(gè)是Iterable眷细,map將傳入的函數(shù)依次作用到序列的每個(gè)元素,并把結(jié)果作為新的Iterator返回鹃祖。
def f(x):
return x*x
r = map(f, [1,2,3,4])
print(list(r)) # [1,4,9,16]
再看reduce的用法溪椎。reduce把一個(gè)函數(shù)作用在一個(gè)序列[x1, x2, x3, ...]上,這個(gè)函數(shù)必須接收兩個(gè)參數(shù)恬口,reduce把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
filter
和map()類似校读,filter()也接收一個(gè)函數(shù)和一個(gè)序列。和map()不同的是祖能,filter()把傳入的函數(shù)依次作用于每個(gè)元素歉秫,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素
注意到filter()函數(shù)返回的是一個(gè)Iterator,也就是一個(gè)惰性序列养铸,所以要強(qiáng)迫f(wàn)ilter()完成計(jì)算結(jié)果雁芙,需要用list()函數(shù)獲得所有結(jié)果并返回list。
sorted
sorted()函數(shù)也是一個(gè)高階函數(shù)钞螟,它還可以接收一個(gè)key函數(shù)來(lái)實(shí)現(xiàn)自定義的排序兔甘,例如按絕對(duì)值大小排序
sorted([36, 5, -12, 9, -21], key=abs)
函數(shù)作為返回值
我們來(lái)實(shí)現(xiàn)一個(gè)可變參數(shù)的求和。通常情況下鳞滨,求和的函數(shù)是這樣定義的
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
但是洞焙,如果不需要立刻求和,而是在后面的代碼中拯啦,根據(jù)需要再計(jì)算怎么辦闽晦?可以不返回求和的結(jié)果,而是返回求和的函數(shù)
def lazy_sum(*args):
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
return calc_sum
閉包
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
全部都是9提岔!原因就在于返回的函數(shù)引用了變量i仙蛉,但它并非立刻執(zhí)行。等到3個(gè)函數(shù)都返回時(shí)碱蒙,它們所引用的變量i已經(jīng)變成了3荠瘪,因此最終結(jié)果為9
返回閉包時(shí)牢記一點(diǎn):返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量赛惩。
如果一定要引用循環(huán)變量怎么辦哀墓?方法是再創(chuàng)建一個(gè)函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量當(dāng)前的值喷兼,無(wú)論該循環(huán)變量后續(xù)如何更改篮绰,已綁定到函數(shù)參數(shù)的值不變:
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被執(zhí)行,因此i的當(dāng)前值被傳入f()
return fs
裝飾器
本質(zhì)上季惯,decorator就是一個(gè)返回函數(shù)的高階函數(shù)吠各。所以臀突,我們要定義一個(gè)能打印日志的decorator
import functools
def log(func):
@functools.wraps(func)
def wrapper(*arg,**kw):
print('call %s',%func.__name__)
return func(*arg, **kw)
return wrapper
@log
def now():
print('2015-3-25')
如果decorator本身需要傳入?yún)?shù),那就需要編寫一個(gè)返回decorator的高階函數(shù)贾漏,寫出來(lái)會(huì)更復(fù)雜候学。比如,要自定義log的文本
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print('2015-3-25')