今天看了函數(shù)式編程的內(nèi)容诫龙,需要記錄一下。
高階函數(shù)
map/reduce
- map()函數(shù)
它接受兩個(gè)參數(shù),一個(gè)函數(shù)歧焦,一個(gè)Iterable,這個(gè)函數(shù)會(huì)作用于Iterable的每個(gè)元素肚医,并把結(jié)果作為Iterator返回绢馍。
比如:
>>> def f(x):
... return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
可見最后的結(jié)果是list中的每個(gè)元素都進(jìn)行平方運(yùn)算最后生成一個(gè)Iterator,然后用list方法進(jìn)行輸出肠套。
- reduce()函數(shù)
它接受兩個(gè)參數(shù)舰涌,一個(gè)函數(shù),一個(gè)序列你稚,用于把結(jié)果繼續(xù)和序列的下個(gè)元素做累積計(jì)算瓷耙。
比如:
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
...
>>> reduce(fn, [1, 3, 5, 7, 9])
13579
list的前面兩個(gè)元素做出的結(jié)果繼續(xù)與后面的元素進(jìn)行運(yùn)算朱躺,以此類推。
filter
它也接受一個(gè)函數(shù)和一個(gè)序列作為參數(shù)搁痛,然后把傳入的函數(shù)作用于序列中的每個(gè)元素长搀,再根據(jù)返回的是True還是False決定保留或者刪去元素。
比如:
>>> def is_odd(n):
... return n % 2 == 0
>>> list(filter(is_odd,[2,3,4,5,7,9,10]))
[2, 4, 10]
這個(gè)函數(shù)就可以保留偶數(shù)鸡典。
sorted
一般的排序用法源请。
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
或者
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
可以用key來指定排序的關(guān)鍵字。
當(dāng)需要反向排序的時(shí)候可以這樣:
sorted([-21, -12, 5, 9, 36],reverse=True)
[36, 9, 5, -12, -21]
加上reverse方法即可彻况。
返回函數(shù)
- 函數(shù)可以當(dāng)做結(jié)果值返回谁尸。
比如這個(gè)求和函數(shù):
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
我們發(fā)現(xiàn)調(diào)用后返回的是一個(gè)函數(shù)而不是值,之后再次進(jìn)行調(diào)用才可以纽甘。
>>> f()
25
當(dāng)程序修改后才回返回計(jì)算的值:
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum()
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
25
- 閉包
這樣兩個(gè)函數(shù):
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f())
return fs
f1, f2, f3 = count()
print(f1,f2,f3)
輸出1 4 9
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
print(f1(),f2(),f3())
輸出9 9 9
差別在哪里良蛮?
前者加入fs這個(gè)list的其實(shí)是經(jīng)過計(jì)算后的值,也就是1悍赢、4决瞳、9。那么count()調(diào)用后就已經(jīng)進(jìn)行了運(yùn)算泽裳,所以f1瞒斩、f2、f3就分別對(duì)應(yīng)的是list的三個(gè)值涮总。
后者加入list的其實(shí)是三個(gè)函數(shù)胸囱,都是計(jì)算i*i的函數(shù),也就是f1瀑梗、f2烹笔、f3這三個(gè)元素。只有最后調(diào)用的時(shí)候才產(chǎn)生結(jié)果抛丽,那么調(diào)用的時(shí)候i已經(jīng)是3了谤职,所以結(jié)果相同了都是9。
匿名函數(shù)
匿名函數(shù)用法:
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
lambda x: x * x就是匿名函數(shù)亿鲜。
裝飾器
在代碼運(yùn)行期間動(dòng)態(tài)增加功能的方式允蜈,稱為“裝飾器”。
- 函數(shù)的名字
函數(shù)對(duì)象有個(gè)name屬性蒿柳,可以拿到函數(shù)的名字饶套,比如:
>>> int.__name__
'int'
- 要增強(qiáng)某個(gè)函數(shù)的功能,希望在調(diào)用前后打印日志垒探。
比如:
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
利用@語法:
@log
def now():
print('2015-3-25')
調(diào)用now()函數(shù):
>>> now()
call now():
2015-3-25
發(fā)現(xiàn)進(jìn)行了日志輸出妓蛮。
偏函數(shù)
普通情況下,int會(huì)把字符串轉(zhuǎn)換為整數(shù)圾叼,比如:
>>> int('12345')
12345
但是int()函數(shù)還提供額外的base參數(shù)蛤克,比如:
>>> int('12345', base=8)
5349
>>> int('12345', 16)
74565
利用偏函數(shù):
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
這樣重新定義后的int2函數(shù)就可以把二進(jìn)制字符串轉(zhuǎn)化為十進(jìn)制數(shù)了捺癞。