Python學習之函數式編程
Linux編程
點擊右側關注,免費入門到精通!
作者丨stone_zhu
https://www.jianshu.com/p/efa8925e0256
高階函數
在python中函數名是指向函數的變數,當函數的參數也是函數的時候,這種函數我們稱之為高階函數。
def
add
(x, y, f)
:return
f(x) + f(y)add(
1
,-6
, abs)map/reduce
map()函數接收兩個參數,一個是函數,一個是Iterable,map將傳入的函數依次作用到序列的每個元素,並把結果作為新的Iterator返回。
def f (x)
return
x * x
r = map(f, [
1
,2
,3
,4
,5
,6
,7
,8
,9
])print(list(r))
>>
> [
1
,4
,9
,16
,25
,36
,49
,64
,81
]reduce把一個函數作用在一個序列[x1, x2, x3, ...]上,這個函數必須接收兩個參數,reduce把結果繼續和序列的下一個元素做累積計算,效果如下:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
結合map和reduce可以整理出一個str2int的函數:
from import
DIGITS = {
"0"
:0
,"1"
:1
,"2"
:2
,"3"
:3
,"4"
:4
,"5"
:5
,"6"
:6
,"7"
:7
,"8"
:8
,"9"
:9
}def
char2num
(s)
:return
DIGITS[s]def
str2int
(s)
:return
reduce(lambda
x, y: x *10
+ y, map(char2num, s))filter
Python內建的filter()函數用於過濾序列。
和map()類似,filter()也接收一個函數和一個序列。和map()不同的是,filter()把傳入的函數依次作用於每個元素,然後根據返回值是True還是False決定保留還是丟棄該元素。
例如,在一個list中,刪掉偶數,只保留奇數,可以這麼寫:
def is_odd (n)
return
n %2
==1
list(filter(is_odd, [
1
,2
,4
,5
,6
,9
,10
,15
]))# 結果: [1, 5, 9, 15]
sorted
對list進行排序:
sorted [36, 5, -12, 9, -21] [-21, -12, 5, 9, 36]>>>
此外,sorted()函數也是一個高階函數,它還可以接收一個key函數來實現自定義的排序,例如按絕對值大小排序:
>> 36 5 12 9 21 5 9 12 21 36
[
字元串排序:
>> "bob" "about" "Zoo" "Credit" "Credit" "Zoo" "about" "bob"
[
忽略大小寫:
>> "bob" "about" "Zoo" "Credit" "about" "bob" "Credit" "Zoo"
[
要進行反向排序,不必改動key函數,可以傳入第三個參數reverse=True
>> "bob" "about" "Zoo" "Credit" "Zoo" "Credit" "bob" "about"
[
返回函數
定義
高階函數除了可以接受函數作為參數外,還可以把函數作為結果值返回。
我們來實現一個可變參數的求和。通常情況下,求和的函數是這樣定義的:
def calc_sum (*args)
ax =
0
for
nin
args:ax = ax + n
return
ax但是,如果不需要立刻求和,而是在後面的代碼中,根據需要再計算怎麼辦?可以不返回求和的結果,而是返回求和的函數:
def lazy_sum (*args)
def
sum
()
:ax =
0
for
nin
args:ax = ax + n
return
axreturn
sum當我們調用lazy_sum()時,返回的並不是求和結果,而是求和函數:
>> 1 3 5 7 9 >> 0x101c6ed90
<function lazy_sum.<locals>.sum at
調用函數f時,才真正計算求和的結果
>> 25
閉包
如上所示的例子中,我們在函數lazy_sum中又定義了函數sum,並且,內部函數sum可以引用外部函數lazy_sum的參數和局部變數,當lazy_sum返回函數sum時,相關參數和變數都保存在返回的函數中,這種稱為「閉包(Closure)」。
注意點:返回函數不要引用任何循環變數,或者後續會發生變化的變數。
如下所示:
def count ()
fs = []
for
iin
range(1
,4
):def
f
()
:return
i*ifs.append(f)
return
fsf1, f2, f3 = count()
返回結果如下:
>> 9 >> 9 >> 9
匿名函數
關鍵字lambda表示匿名函數,冒號前面的x表示函數參數。匿名函數有個限制,就是只能有一個表達式,不用寫return,返回值就是該表達式的結果。
list map 1 2 3 4 5 6 7 8 9 1 4 9 16 25 36 49 64 81>>>
[
裝飾器
代碼運行期間動態增加功能的方式,稱之為「裝飾器」(Decorator)。本質上,decorator就是一個返回函數的高階函數。
定義一個能列印日誌的decorator,可以定義如下:
def log (func)
def
wrapper
(*args, **kw)
:print(
"call %s():"
% func.__name__)return
func(*args, **kw)return
wrapper觀察上面的log,因為它是一個decorator,所以接受一個函數作為參數,並返回一個函數。我們要藉助Python的@語法,把decorator置於函數的定義處:
def now ()@log
print(
"2015-3-25"
)>>
> now()call now():
2015
-3
-25
把@log放到now()函數的定義處,相當於執行了語句:now = log(now),now變數指向了新的函數。
如果decorator本身需要傳入參數,那就需要編寫一個返回decorator的高階函數,寫出來會更複雜。比如,要自定義log的文本:
def log (text)
def
decorator
(func)
:def
wrapper
(*args, **kw)
:print(
"%s %s():"
% (text, func.__name__))return
func(*args, **kw)return
wrapperreturn
decorator這個3層嵌套的decorator用法如下:
"execute" def now ()@log(
print(
"2015-3-25"
)>>
> now()execute now():
2015
-3
-25
和兩層嵌套的decorator相比,3層嵌套的效果是這樣的:>>> now = log("execute")(now)
有個問題,經過decorator裝飾之後的函數,它們的
name
已經從原來的"now"變成了"wrapper":>> _ "wrapper"
Python內置的functools.wraps用來複制函數name屬性的:
import
def
log
(func)
:@functools.wraps(func)
def
wrapper
(*args, **kw)
:print(
"call %s():"
% func.__name__)return
func(*args, **kw)return
wrapper或者針對帶參數的裝飾器:
import
def
log
(text)
:def
decorator
(func)
:@functools.wraps(func)
def
wrapper
(*args, **kw)
:print(
"%s %s():"
% (text, func.__name__))return
func(*args, **kw)return
wrapperreturn
decorator偏函數
Python的functools模塊提供了很多有用的功能,其中一個就是偏函數(Partial function)。把一個函數的某些參數給固定住(也就是設置默認值),返回一個新的函數,調用這個新函數會更簡單。
創建偏函數時,實際上可以接收函數對象、args和*kw這3個參數。
比如要使用int()函數去轉換二進位字元串,原本的寫法是:int(x, base=2),如果量大的話,很麻煩,所以我們可以這麼寫:
>> >> 2 >> "1000000" 64 >> "1010101" 85
上面的in2 = functools.partial(int, base=2)相當於:
"base" 2 int "10010"kw = {
【點擊成為編程大牛】
※Python面試必須要看的15個問題
※你沐浴後的味道,根本讓人把持不住!留香24小時,比噴了大牌香水還迷人!
TAG:Python開發 |